Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * OpenTyrian: A modern cross-platform port of Tyrian
  3.  * Copyright (C) 2007-2009  The OpenTyrian Development Team
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  18.  */
  19. #include "loudness.h"
  20.  
  21. #include "file.h"
  22. #include "lds_play.h"
  23. #include "nortsong.h"
  24. #include "opentyr.h"
  25. #include "params.h"
  26.  
  27. float music_volume = 0, sample_volume = 0;
  28.  
  29. bool music_stopped = true;
  30. unsigned int song_playing = 0;
  31.  
  32. bool audio_disabled = false, music_disabled = false, samples_disabled = false;
  33.  
  34. /* SYN: These shouldn't be used outside this file. Hands off! */
  35. FILE *music_file = NULL;
  36. Uint32 *song_offset;
  37. Uint16 song_count = 0;
  38.  
  39.  
  40. SAMPLE_TYPE *channel_buffer[SFX_CHANNELS] = { NULL };
  41. SAMPLE_TYPE *channel_pos[SFX_CHANNELS] = { NULL };
  42. Uint32 channel_len[SFX_CHANNELS] = { 0 };
  43. Uint8 channel_vol[SFX_CHANNELS];
  44.  
  45. int sound_init_state = false;
  46. int freq = 11025 * OUTPUT_QUALITY;
  47.  
  48. static SDL_AudioCVT audio_cvt; // used for format conversion
  49.  
  50. void audio_cb( void *userdata, unsigned char *feedme, int howmuch );
  51.  
  52. void load_song( unsigned int song_num );
  53.  
  54. bool init_audio( void )
  55. {
  56.         if (audio_disabled)
  57.                 return false;
  58.        
  59.         SDL_AudioSpec ask, got;
  60.        
  61.         ask.freq = freq;
  62.         ask.format = (BYTES_PER_SAMPLE == 2) ? AUDIO_S16SYS : AUDIO_S8;
  63.         ask.channels = 1;
  64.         ask.samples = 2048;
  65.         ask.callback = audio_cb;
  66.        
  67.         printf("\trequested %d Hz, %d channels, %d samples\n", ask.freq, ask.channels, ask.samples);
  68.        
  69.         #ifdef _KOLIBRI
  70.         SDL_AudioInit(NULL);
  71.         #endif
  72.  
  73.         if (SDL_OpenAudio(&ask, &got) == -1)
  74.         {
  75.                 fprintf(stderr, "error: failed to initialize SDL audio: %s\n", SDL_GetError());
  76.                 audio_disabled = true;
  77.                 return false;
  78.         }
  79.        
  80.         printf("\tobtained  %d Hz, %d channels, %d samples\n", got.freq, got.channels, got.samples);
  81.        
  82.         SDL_BuildAudioCVT(&audio_cvt, ask.format, ask.channels, ask.freq, got.format, got.channels, got.freq);
  83.        
  84.         opl_init();
  85.        
  86.         SDL_PauseAudio(0); // unpause
  87.        
  88.         return true;
  89. }
  90.  
  91. void audio_cb( void *user_data, unsigned char *sdl_buffer, int howmuch )
  92. {
  93.         (void)user_data;
  94.        
  95.         // prepare for conversion
  96.         howmuch /= audio_cvt.len_mult;
  97.         audio_cvt.buf = sdl_buffer;
  98.         audio_cvt.len = howmuch;
  99.        
  100.         static long ct = 0;
  101.        
  102.         SAMPLE_TYPE *feedme = (SAMPLE_TYPE *)sdl_buffer;
  103.  
  104.         if (!music_disabled && !music_stopped)
  105.         {
  106.                 /* SYN: Simulate the fm synth chip */
  107.                 SAMPLE_TYPE *music_pos = feedme;
  108.                 long remaining = howmuch / BYTES_PER_SAMPLE;
  109.                 while (remaining > 0)
  110.                 {
  111.                         while (ct < 0)
  112.                         {
  113.                                 ct += freq;
  114.                                 lds_update(); /* SYN: Do I need to use the return value for anything here? */
  115.                         }
  116.                         /* SYN: Okay, about the calculations below. I still don't 100% get what's going on, but...
  117.                         - freq is samples/time as output by SDL.
  118.                         - REFRESH is how often the play proc would have been called in Tyrian. Standard speed is
  119.                         70Hz, which is the default value of 70.0f
  120.                         - ct represents the margin between play time (representing # of samples) and tick speed of
  121.                         the songs (70Hz by default). It keeps track of which one is ahead, because they don't
  122.                         synch perfectly. */
  123.                        
  124.                         /* set i to smaller of data requested by SDL and a value calculated from the refresh rate */
  125.                         long i = (long)((ct / REFRESH) + 4) & ~3;
  126.                         i = (i > remaining) ? remaining : i; /* i should now equal the number of samples we get */
  127.                         opl_update((SAMPLE_TYPE *)music_pos, i);
  128.                         music_pos += i;
  129.                         remaining -= i;
  130.                         ct -= (long)(REFRESH * i);
  131.                 }
  132.                
  133.                 /* Reduce the music volume. */
  134.                 int qu = howmuch / BYTES_PER_SAMPLE;
  135.                 for (int smp = 0; smp < qu; smp++)
  136.                 {
  137.                         feedme[smp] *= music_volume;
  138.                 }
  139.         }
  140.        
  141.         if (!samples_disabled)
  142.         {
  143.                 /* SYN: Mix sound channels and shove into audio buffer */
  144.                 for (int ch = 0; ch < SFX_CHANNELS; ch++)
  145.                 {
  146.                         float volume = sample_volume * (channel_vol[ch] / (float)SFX_CHANNELS);
  147.                        
  148.                         /* SYN: Don't copy more data than is in the channel! */
  149.                         unsigned int qu = ((unsigned)howmuch > channel_len[ch] ? channel_len[ch] : (unsigned)howmuch) / BYTES_PER_SAMPLE;
  150.                         for (unsigned int smp = 0; smp < qu; smp++)
  151.                         {
  152. #if (BYTES_PER_SAMPLE == 2)
  153.                                 Sint32 clip = (Sint32)feedme[smp] + (Sint32)(channel_pos[ch][smp] * volume);
  154.                                 feedme[smp] = (clip > 0x7fff) ? 0x7fff : (clip <= -0x8000) ? -0x8000 : (Sint16)clip;
  155. #else  /* BYTES_PER_SAMPLE */
  156.                                 Sint16 clip = (Sint16)feedme[smp] + (Sint16)(channel_pos[ch][smp] * volume);
  157.                                 feedme[smp] = (clip > 0x7f) ? 0x7f : (clip <= -0x80) ? -0x80 : (Sint8)clip;
  158. #endif  /* BYTES_PER_SAMPLE */
  159.                         }
  160.                        
  161.                         channel_pos[ch] += qu;
  162.                         channel_len[ch] -= qu * BYTES_PER_SAMPLE;
  163.                        
  164.                         /* SYN: If we've emptied a channel buffer, let's free the memory and clear the channel. */
  165.                         if (channel_len[ch] == 0)
  166.                         {
  167.                                 free(channel_buffer[ch]);
  168.                                 channel_buffer[ch] = channel_pos[ch] = NULL;
  169.                         }
  170.                 }
  171.         }
  172.        
  173.         // do conversion
  174.         SDL_ConvertAudio(&audio_cvt);
  175. }
  176.  
  177. void deinit_audio( void )
  178. {
  179.         if (audio_disabled)
  180.                 return;
  181.        
  182.         SDL_PauseAudio(1); // pause
  183.        
  184.         SDL_CloseAudio();
  185.        
  186.         for (unsigned int i = 0; i < SFX_CHANNELS; i++)
  187.         {
  188.                 free(channel_buffer[i]);
  189.                 channel_buffer[i] = channel_pos[i] = NULL;
  190.                 channel_len[i] = 0;
  191.         }
  192.        
  193.         lds_free();
  194. }
  195.  
  196.  
  197. void load_music( void )
  198. {
  199.         if (music_file == NULL)
  200.         {
  201.                 music_file = dir_fopen_die(data_dir(), "music.mus", "rb");
  202.                
  203.                 efread(&song_count, sizeof(song_count), 1, music_file);
  204.                
  205.                 song_offset = malloc((song_count + 1) * sizeof(*song_offset));
  206.                
  207.                 efread(song_offset, 4, song_count, music_file);
  208.                 song_offset[song_count] = ftell_eof(music_file);
  209.         }
  210. }
  211.  
  212. void load_song( unsigned int song_num )
  213. {
  214.         if (audio_disabled)
  215.                 return;
  216.        
  217.         SDL_LockAudio();
  218.        
  219.         if (song_num < song_count)
  220.         {
  221.                 unsigned int song_size = song_offset[song_num + 1] - song_offset[song_num];
  222.                 lds_load(music_file, song_offset[song_num], song_size);
  223.         }
  224.         else
  225.         {
  226.                 fprintf(stderr, "warning: failed to load song %d\n", song_num + 1);
  227.         }
  228.        
  229.         SDL_UnlockAudio();
  230. }
  231.  
  232. void play_song( unsigned int song_num )
  233. {
  234.         if (song_num != song_playing)
  235.         {
  236.                 load_song(song_num);
  237.                 song_playing = song_num;
  238.         }
  239.        
  240.         music_stopped = false;
  241. }
  242.  
  243. void restart_song( void )
  244. {
  245.         unsigned int temp = song_playing;
  246.         song_playing = -1;
  247.         play_song(temp);
  248. }
  249.  
  250. void stop_song( void )
  251. {
  252.         music_stopped = true;
  253. }
  254.  
  255. void fade_song( void )
  256. {
  257.         /* STUB: we have no implementation of this to port */
  258. }
  259.  
  260. void set_volume( unsigned int music, unsigned int sample )
  261. {
  262.         music_volume = music * (1.5f / 255.0f);
  263.         sample_volume = sample * (1.0f / 255.0f);
  264. }
  265.  
  266. void JE_multiSamplePlay(JE_byte *buffer, JE_word size, JE_byte chan, JE_byte vol)
  267. {
  268.         if (audio_disabled || samples_disabled)
  269.                 return;
  270.        
  271.         SDL_LockAudio();
  272.        
  273.         free(channel_buffer[chan]);
  274.        
  275.         channel_len[chan] = size * BYTES_PER_SAMPLE * SAMPLE_SCALING;
  276.         channel_buffer[chan] = malloc(channel_len[chan]);
  277.         channel_pos[chan] = channel_buffer[chan];
  278.         channel_vol[chan] = vol + 1;
  279.  
  280.         for (int i = 0; i < size; i++)
  281.         {
  282.                 for (int ex = 0; ex < SAMPLE_SCALING; ex++)
  283.                 {
  284. #if (BYTES_PER_SAMPLE == 2)
  285.                         channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i] << 8;
  286. #else  /* BYTES_PER_SAMPLE */
  287.                         channel_buffer[chan][(i * SAMPLE_SCALING) + ex] = (Sint8)buffer[i];
  288. #endif  /* BYTES_PER_SAMPLE */
  289.                 }
  290.         }
  291.  
  292.         SDL_UnlockAudio();
  293. }
  294.  
  295.