1 /*  sound.c */
2 
3 /*  Copyright Hugh Robinson 2006-2008.
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (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, see <http://www.gnu.org/licenses/>. */
17 
18 #include <SDL/SDL_mixer.h>
19 #include <math.h>
20 #include "asylum.h"
21 
22 extern asylum_options options;
23 char sound_available;
24 
bidforsoundforce(int r0,char r1,char r2,int r3,int r4,int r5,char r6,int r7,Mix_Chunk * chunk)25 void bidforsoundforce(int r0, char r1, char r2, int r3, int r4, int r5, char r6, int r7, Mix_Chunk* chunk)
26 {
27   if (options.soundtype && sound_available)
28   {
29     r2 = (r2 > options.soundvol) ? options.soundvol : r2;
30     soundclaim(r0&7, r1, r2, r3, r4, r5, r6, r7, chunk);
31   }
32 }
33 
bidforsound(int r0,char r1,char r2,int r3,int r4,int r5,char r6,int r7,Mix_Chunk * chunk)34 void bidforsound(int r0, char r1, char r2, int r3, int r4, int r5, char r6, int r7, Mix_Chunk* chunk)
35 {
36   if (options.soundtype && sound_available)
37   {
38     r2 = (r2 > options.soundvol) ? options.soundvol : r2;
39     if ((r0&7)==_Explochannel)
40       soundclaimexplo(r0&7, r1, r2, r3, r4, r5, r6, r7, chunk);
41     else
42       soundclaimmaybe(r0&7, r1, r2, r3, r4, r5, r6, r7, chunk);
43   }
44 }
45 
soundclaimmaybe(int r0,char r1,char r2,int r3,int r4,int r5,char r6,int r7,Mix_Chunk * chunk)46 void soundclaimmaybe(int r0, char r1, char r2, int r3, int r4, int r5, char r6, int r7, Mix_Chunk* chunk)
47 {
48 //soundtab=soundtabofs+(r0<<soundtabshift);
49     if ((!Mix_Playing(r0)) || (Mix_GetChunk(r0)->volume < r2)) soundclaim(r0, r1, r2, r3, r4, r5, r6, r7, chunk);
50 }
51 
soundclaimexplo(int r0,char r1,char r2,int r3,int r4,int r5,char r6,int r7,Mix_Chunk * chunk)52 void soundclaimexplo(int r0, char r1, char r2, int r3, int r4, int r5, char r6, int r7, Mix_Chunk* chunk)
53 {
54 //soundtab=soundtabofs+(r0<<soundtabshift);
55    bidforexplo:
56     if ((!Mix_Playing(3)) || (Mix_GetChunk(3)->volume < r2)) soundclaim(3, r1, r2, r3, r4, r5, r6, r7, chunk);
57     else if ((!Mix_Playing(4)) || (Mix_GetChunk(4)->volume < r2)) soundclaim(4, r1, r2, r3, r4, r5, r6, r7, chunk);
58     else if ((!Mix_Playing(5)) || (Mix_GetChunk(5)->volume < r2)) soundclaim(5, r1, r2, r3, r4, r5, r6, r7, chunk);
59     else if ((!Mix_Playing(6)) || (Mix_GetChunk(6)->volume < r2)) soundclaim(6, r1, r2, r3, r4, r5, r6, r7, chunk);
60     else if ((!Mix_Playing(7)) || (Mix_GetChunk(7)->volume < r2)) soundclaim(7, r1, r2, r3, r4, r5, r6, r7, chunk);
61 }
62 
63 typedef struct
64 {
65     int time;
66     int tempo;
67     char* tune;
68     int pitch[4];
69     int inst[4];
70     int start_time[4];
71     char* section;
72     int pointer;
73 } music_state;
74 music_state music;
75 char voice[32][30000];
76 char tuneload[4][30000];
77 Sint16 mulaw[256];
78 Mix_Music* oggmusic[4];
79 
init_audio()80 void init_audio()
81 {
82     sound_available = !Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 1024);
83     if (!sound_available) fprintf(stderr, "Sound disabled: opening audio device failed: %s\n", Mix_GetError());
84 }
85 
init_mulaw()86 void init_mulaw()
87 {
88     Sint16 exp[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
89     for (int i = 0; i < 256; i++)
90         mulaw[i] = ((i&1) ? -1 : 1)*(exp[i>>5]+((i&0x1e)<<(2+(i>>5))));
91 }
92 
make_sound(char samp,int initpitch,int volslide,int pitchslide,char frames)93 Mix_Chunk* make_sound(char samp, int initpitch, int volslide, int pitchslide, char frames)
94 {
95     int numsamples = (int)(frames*22050.0/50.0*2); // frames are 50Hz?
96     Mix_Chunk* mc = (Mix_Chunk*)malloc(sizeof(Mix_Chunk));
97     Uint16* s = (Uint16*)malloc(numsamples*2*sizeof(Uint16));
98 
99     mc->abuf = (Uint8*)s;
100     mc->alen = numsamples*2*sizeof(Uint16);
101     mc->allocated = 0; // don't automatically free buffer
102     mc->volume = 0xff; // XXX volume
103     int time = 0;
104     double ps = ((Sint16)(pitchslide&0xffff))*22/22050.0;
105     double vs = ((Sint16)(volslide&0xffff))/22050.0;
106     Sint16 psmax = pitchslide>>16;
107     double matching = 0;
108     fprintf(stderr, "."); fflush(stderr);
109     for (int i = 0; i < numsamples*2*sizeof(Uint16); i += 4, time++, s += 2)
110     {
111         Uint16 mono = 0;
112 
113         double pitch = initpitch+ps*time; // XXX pitchslide
114         //if ((ps>0)&&(pitch>psmax)) pitch=psmax;
115         //if ((ps<0)&&(pitch<psmax)) pitch=psmax;
116         int off = time;
117         double old_sample_rate = 500.0*pow(2, pitch/4096.0);
118         matching += old_sample_rate/22050;
119         for (int j = (int)matching-32; j <= (int)matching+32; j++)
120         {
121             if ((j < 0)) continue;
122             int jj = j;
123             uint32_t len = read_littleendian(((uint32_t*)voice[samp])+6);
124             uint32_t gap = read_littleendian(((uint32_t*)voice[samp])+7); // ???
125             uint32_t rep = read_littleendian(((uint32_t*)voice[samp])+8);
126             if (jj >= len) if (rep == 0) continue;else jj = (len-rep)+((jj-len)%rep);double w;
127             if (jj >= len-gap)
128                 w = ((jj-(len-gap))*(double)mulaw[voice[samp][jj+44-rep]]
129                      +(len-jj)*(double)mulaw[voice[samp][jj+44]])/gap/4;
130             else w = mulaw[voice[samp][jj+44]]/4;
131             double vscale = 0x7f+vs*time;
132             if (vscale > 0xff) vscale = 0xff;
133             if (vscale > 0) w *= (vscale/0x7f);else w = 0;
134             double x = M_PI*(j-matching);
135             if (x == 0) mono += (Sint16)(w/1.3);
136             else mono += (Sint16)(w*sinf(x)/(1.3*x));
137         }
138         s[1] = *s = mono; // XXX stereo
139     }
140     return mc;
141 }
142 
soundclaim(int c,char samp,char initvol,int initpitch,int volslide,int pitchslide,char frames,int stereo,Mix_Chunk * static_chunk)143 void soundclaim(int c, char samp, char initvol, int initpitch, int volslide, int pitchslide, char frames, int stereo, Mix_Chunk* static_chunk)
144 {
145     //int* argv = (int*)vargv;
146     //int c = argv[0]; char samp = argv[1]; char initvol = argv[2]; int initpitch = argv[3];
147     //int volslide = argv[4]; int pitchslide = argv[5]; char frames = argv[6]; int stereo = argv[7];
148     Mix_Chunk* old_chunk = Mix_GetChunk(c);
149     Mix_Chunk* chunk = static_chunk ? static_chunk : make_sound(samp, initpitch, volslide, pitchslide, frames);
150 
151     Mix_HaltChannel(c);
152     Mix_Volume(c, initvol);
153     Mix_SetPanning(c, 254-stereo, stereo);
154     Mix_PlayChannel(c, chunk, 0);
155     //if (old_chunk) Mix_FreeChunk(old_chunk); XXX memory leak
156 }
157 
158 FILE* musicdumpfile;
159 
sdl_music_hook(void * udata,Uint8 * stream,int len)160 void sdl_music_hook(void* udata, Uint8* stream, int len)
161 {
162     music_state* m = (music_state*)udata;
163     char* tuneload = m->tune;
164     Sint16* s = (Sint16*)stream;
165     int window = (len < 0) ? 16 : 4;
166     unsigned long ln = (len < 0) ? -ftell(musicdumpfile) : 0;
167 
168     for (int i = 0; (len < 0) || (i < len); i += 4, m->time++, (len < 0) || (s += 2))
169     {
170         if (0 == (m->time%m->tempo))
171         {
172             // new beat
173             if (len == -2)
174             {
175                 ln += ftell(musicdumpfile); fseek(musicdumpfile, 8, 0);
176                 fputc(ln>>24, musicdumpfile); fputc((ln&0xff0000)>>16, musicdumpfile);
177                 fputc((ln&0xff00)>>8, musicdumpfile); fputc(ln&0xff, musicdumpfile);
178                 break;
179             }
180             int inst = 0;
181             int pitch = 8;
182             char first;
183             char second;
184             do
185             {
186                 first = tuneload[m->pointer++];
187                 second = tuneload[m->pointer++];
188                 if (first)
189                 { // pitch word
190                     inst = first&0x1f;
191                     pitch = second&0x3f;
192                 }
193                 else
194                 {
195                     m->pitch[second&3] = pitch;
196                     m->inst[second&3] = inst;
197                     m->start_time[second&3] = m->time;
198                     inst = 0; pitch = 8;
199                 }
200             }
201             while ((second&0xc0) == 0);
202             if (second&0x80)
203             {
204                 m->section++;
205                 if (0x80&*m->section)
206                 {
207                     m->section = tuneload+8; if (len < 0) len = -2;
208                 }
209                 m->pointer = read_littleendian(((uint32_t*)tuneload)+0x42+*m->section);
210             }
211         }
212         *s = 0; s[1] = 0;
213         for (int v = 0; v < 4; v++)
214         {
215             if (m->inst[v] == 0) continue;
216             int pitch = m->pitch[v];
217             int off = m->time-m->start_time[v];
218             double old_sample_rate = 4000.0*pow(2, pitch/12.0);
219             double matching = off*old_sample_rate/22050;
220             for (int j = (int)matching-window; j <= (int)matching+window; j++)
221             {
222                 if ((j < 0)) continue;
223                 int jj = j;
224                 uint32_t len = read_littleendian(((uint32_t*)voice[m->inst[v]])+6);
225                 uint32_t gap = read_littleendian(((uint32_t*)voice[m->inst[v]])+7); // ???
226                 uint32_t rep = read_littleendian(((uint32_t*)voice[m->inst[v]])+8);
227                 /*if (m->inst[v]==16)
228                    while (jj>=6960+1000) jj-=6960;
229                    else
230                    if (jj>=8192) continue;*/
231                 if (jj >= len) jj = rep ? ((len-rep)+((jj-len)%rep)) : 0;
232                 double w;
233                 if (jj >= len-gap)
234                     w = ((jj-(len-gap))*(double)mulaw[voice[m->inst[v]][jj+44-rep]]
235                          +(len-jj)*(double)mulaw[voice[m->inst[v]][jj+44]])/gap/4;
236                 else w = mulaw[voice[m->inst[v]][jj+44]]/4;
237                 double x = M_PI*(j-matching);
238                 if (x == 0) s[v&1] += (Sint16)(w/1.3);
239                 else s[v&1] += (Sint16)(w*sinf(x)/(1.3*x));
240             }
241         }
242         if (len < 0)
243         {
244             /* .au is big-endian format */
245             fputc(s[0]>>8, musicdumpfile);
246             fputc(s[0]&0xff, musicdumpfile);
247             fputc(s[1]>>8, musicdumpfile);
248             fputc(s[1]&0xff, musicdumpfile);
249         }
250     }
251 }
252 
load_voices()253 void load_voices()
254 {
255     if (!sound_available) return;
256     load_voice(1, "./Voices/Jump");
257     load_voice(2, "./Voices/Bonus");
258     load_voice(3, "./Voices/Explo");
259     load_voice(4, "./Voices/AtomExplo");
260     load_voice(5, "./Voices/Cannon");
261     load_voice(6, "./Voices/Rocket");
262     load_voice(7, "./Voices/Hiss");
263     load_voice(8, "./Voices/Stunned");
264     load_voice(9, "./Voices/SmallZap");
265     load_voice(10, "./Voices/BigZap");
266     load_voice(16, "./Voices/Organ");
267     load_voice(17, "./Voices/Plink");
268     load_voice(18, "./Voices/PlinkHard");
269     load_voice(19, "./Voices/Raver");
270     load_voice(20, "./Voices/Dome");
271     load_voice(21, "./Voices/NasalStr");
272     load_voice(22, "./Voices/BassHollow");
273     load_voice(23, "./Voices/NasalBass");
274     load_voice(24, "./Voices/BassDrum");
275     load_voice(25, "./Voices/Snare");
276     load_voice(26, "./Voices/Cymbal");
277 }
278 
init_sounds()279 void init_sounds()
280 {
281     if (!sound_available) return;
282     init_mulaw();
283     fprintf(stderr, "Building sound effects ");
284     init_chunk_bullet();
285     init_chunk_player();
286     init_chunk_alien();
287     init_chunk_maze();
288     fprintf(stderr, " done.\n");
289 }
290 
load_voice(int v,const char * filename)291 void load_voice(int v, const char* filename)
292 {
293     SDL_RWops* file = SDL_RWFromFile(filename, "r");
294 
295     if (file == NULL)
296     {
297         fprintf(stderr, "Loading sound effect %s failed\n", filename);
298         return;
299     }
300     SDL_RWseek(file, 0, SEEK_END);
301     int file_len = SDL_RWtell(file) /*-44*/;
302     SDL_RWseek(file, 0 /*44*/, SEEK_SET);
303     SDL_RWread(file, voice[v], 1, file_len);
304 }
305 
306 
initialize_music(int a)307 void initialize_music(int a)
308 {
309     swi_sound_qtempo(0x1000);
310     music.time = 0;
311     music.tune = tuneload[a];
312     music.section = tuneload[a]+8;
313     music.pointer = read_littleendian(((uint32_t*)(tuneload[a]))+0x42+*music.section);
314     for (int v = 0; v < 4; v++)
315     {
316         music.pitch[v] = 0; music.inst[v] = 0; music.start_time[v] = 0;
317     }
318 }
319 
dumpmusic(int argc,char ** argv)320 void dumpmusic(int argc,char** argv)
321 {
322     init_mulaw();
323     Uint8 wav[4];
324     char musicdumppath[1024] = "";
325     char* musicinputpath = argv[2];
326     strncat(musicdumppath, musicinputpath, 1000);
327     strncat(musicdumppath, ".au", 20);
328     fprintf(stderr, "Dumping music ");
329     //swi_bodgemusic_load(1,musicinputpath);
330     musicdumpfile = fopen(musicdumppath, "w");
331     SDL_RWops* tune = SDL_RWFromFile(musicinputpath, "r");
332     SDL_RWread(tune, tuneload+1, 1, 30000);
333     initialize_music(1);
334     if (argc > 3) if (!strcmp(argv[3], "--slower")) swi_sound_qtempo(0x980);
335     fputs(".snd", musicdumpfile);
336     fputc(0, musicdumpfile); fputc(0, musicdumpfile); fputc(0, musicdumpfile); fputc(32, musicdumpfile);        // data start
337     fputc(255, musicdumpfile); fputc(255, musicdumpfile); fputc(255, musicdumpfile); fputc(255, musicdumpfile); // length
338     fputc(0, musicdumpfile); fputc(0, musicdumpfile); fputc(0, musicdumpfile); fputc(3, musicdumpfile);         // 16-bit linear
339     fputc(0, musicdumpfile); fputc(0, musicdumpfile); fputc(22050>>8, musicdumpfile); fputc(22050&0xff, musicdumpfile);
340     fputc(0, musicdumpfile); fputc(0, musicdumpfile); fputc(0, musicdumpfile); fputc(2, musicdumpfile);         // stereo
341     fputs("blotwell", musicdumpfile);
342     sdl_music_hook(&music, wav+2, -1 /* dump entire track into buffer */);
343     fclose(musicdumpfile);
344     exit(0);
345 }
346 
maketestsound(int r1)347 void maketestsound(int r1)
348 {
349     swi_stasis_link(1, 1);
350     swi_sound_control(1, 0x100|r1, 0x20, 0xfe);
351     //swi_bodgemusic_volume(musicvol);
352 }
swi_bodgemusic_start(int a,int b)353 void swi_bodgemusic_start(int a, int b)
354 {
355     if (!sound_available) return;
356     swi_bodgemusic_stop();
357     if (oggmusic[a]) Mix_PlayMusic(oggmusic[a], -1);
358     else
359     {
360         initialize_music(a);
361         Mix_HookMusic(sdl_music_hook, &music);
362     }
363 }
swi_bodgemusic_stop()364 void swi_bodgemusic_stop()
365 {
366     if (!sound_available) return;
367     Mix_HaltMusic(); Mix_HookMusic(NULL, NULL);
368 }
swi_bodgemusic_volume(int v)369 void swi_bodgemusic_volume(int v)
370 {
371     Mix_VolumeMusic(v);
372 }
swi_bodgemusic_load(int a,char * b)373 void swi_bodgemusic_load(int a, char* b)
374 {
375     char name[1024] = "";
376 
377     strncpy(name, b, 1000);
378     strncat(name, ".ogg", 20);
379     if (oggmusic[a]) Mix_FreeMusic(oggmusic[a]);
380     oggmusic[a] = Mix_LoadMUS(name);
381     if (oggmusic[a]) return;
382     SDL_RWops* tune = SDL_RWFromFile(b, "r");
383     //SDL_RWseek(tune, 8+256+64, SEEK_SET);
384     SDL_RWread(tune, tuneload+a, 1, 30000);
385 }
swi_sound_qtempo(int t)386 void swi_sound_qtempo(int t)
387 {
388     music.tempo = (2756*0x1000)/t;
389 }
swi_sound_control(int c,int a,int p,int d)390 void swi_sound_control(int c, int a, int p, int d)
391 {
392     ;
393 }
swi_sound_speaker(int s)394 int swi_sound_speaker(int s)
395 {
396     ;
397 }
swi_stasis_link(int a,int b)398 void swi_stasis_link(int a, int b)
399 {
400     ;
401 }
swi_stasis_control(int a,int b)402 void swi_stasis_control(int a, int b)
403 {
404     ;
405 }
swi_stasis_volslide(int a,int b,int c)406 void swi_stasis_volslide(int a, int b, int c)
407 {
408     ;
409 }
410