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