OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / sys / amiga / amisnd.c
1 /*      SCCS Id: @(#)amisnd.c   3.2     2000/01/12*/
2 /*      Copyright (c) 1992, 1993, 1995 by Gregg Wonderly */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*
6  * This file contains music playing code.
7  *
8  * If we were REALLY determined, we would make the sound play
9  * asynchronously, but I'll save that one for a rainy day...
10  */
11
12 #include "hack.h"
13 #include "dlb.h"
14
15 #undef red
16 #undef blue
17 #undef green
18 #include <exec/types.h>
19 #include <exec/memory.h>
20 #include <exec/io.h>
21 #include <devices/audio.h>
22 #include <dos/dos.h>
23 #include <dos/dosextens.h>
24 #include <graphics/gfxbase.h>
25
26 #include <proto/exec.h>
27 #include <clib/alib_protos.h>
28 #include <proto/dos.h>
29 #include <proto/graphics.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33
34 #define AMII_AVERAGE_VOLUME     60
35
36 int amii_volume = AMII_AVERAGE_VOLUME;
37
38 typedef struct VHDR
39 {
40         char name[4];
41         long len;
42         unsigned long oneshot, repeat, samples;
43         UWORD freq;
44         UBYTE n_octaves, compress;
45         LONG volume;
46 } VHDR;
47
48 typedef struct IFFHEAD
49 {
50         char FORM[4];
51         long flen;
52         char _8SVX[4];
53         VHDR vhdr;
54         char NAME[4];
55         long namelen;
56 } IFFHEAD;
57
58 extern struct GfxBase *GfxBase;
59
60 UBYTE whichannel[] = { 1, 2, 4, 8 };
61 void makesound( char *, char *, int vol);
62 void amii_speaker( struct obj *instr, char *melody, int vol );
63
64 /* A major scale in indexs to freqtab... */
65 int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
66
67 /* Frequencies for a scale starting at one octave below 'middle C' */
68 long freqtab[] = {
69         220,    /*A */
70         233,    /*Bb*/
71         246,    /*B */
72         261,    /*C */
73         277,    /*Db*/
74         293,    /*D */
75         311,    /*Eb*/
76         329,    /*E */
77         349,    /*F */
78         370,    /*Gb*/
79         392,    /*G */
80         415,    /*Ab*/
81         440,    /*A */
82 };
83
84 #ifdef  TESTING
85 main( argc, argv )
86         int argc;
87         char **argv;
88 {
89         makesound( "wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60 );
90         makesound( "wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60 );
91         makesound( "wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60 );
92         makesound( "wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60 );
93         makesound( "wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60 );
94         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
95         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
96         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
97         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
98         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
99         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
100         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
101         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
102         makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
103 }
104 #else
105 void
106 amii_speaker( struct obj *instr, char *melody, int vol )
107 {
108         int typ = instr->otyp;
109         char * actualn = (char *)OBJ_NAME( objects[typ] ) ;
110
111         /* Make volume be relative to users volume level, with 60 being the
112          * average level that will be passed to us.
113          */
114         vol = vol * amii_volume / AMII_AVERAGE_VOLUME;
115
116         makesound( actualn, melody, vol );
117 }
118 #endif
119
120 void
121 makesound ( char *actualn , char * melody, int vol )
122 {
123         char *t;
124         int c, cycles, dot, dlay;
125         dlb *stream = 0;
126         IFFHEAD iffhead;
127         struct IOAudio *AudioIO = 0;
128         struct MsgPort *AudioMP = 0;
129         struct Message *AudioMSG = 0;
130         ULONG device = -1;
131         BYTE *waveptr = 0;
132         LONG frequency=440, duration=1, clock, samp, samples, samcyc=1;
133         unsigned char name [ 100 ] ;
134
135         if ( flags.silent )
136                 return;
137
138         if( GfxBase->DisplayFlags & PAL )
139                 clock = 3546895;
140         else
141                 clock = 3579545;
142
143         /*
144          * Convert type to file name - if there's nothing to play we
145          * shouldn't be here in the first place.
146          */
147         strncpy(name, actualn,sizeof(name) ) ;
148         for( t = strchr( name, ' ' ); t; t = strchr( name, ' ' ) )
149                 *t = '_';
150         if( (stream = dlb_fopen( name, "r" )) == NULL )
151         {
152             perror( name );
153             return;
154         }
155
156         AudioIO = (struct IOAudio *)
157                 AllocMem( sizeof( struct IOAudio ), MEMF_PUBLIC|MEMF_CLEAR );
158         if( AudioIO == 0 )
159                 goto killaudio;
160
161         AudioMP = CreateMsgPort();
162         if( AudioMP == 0 )
163                 goto killaudio;
164
165         AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
166         AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
167         AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
168         AudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT;
169         AudioIO->ioa_AllocKey = 0;
170         AudioIO->ioa_Data = whichannel;
171         AudioIO->ioa_Length = sizeof( whichannel );
172
173         device = OpenDevice( AUDIONAME, 0L, (struct IORequest *)AudioIO, 0L );
174         if( device != 0 )
175                 goto killaudio;
176
177         if( dlb_fread( (genericptr_t)&iffhead, sizeof( iffhead ), 1, stream ) != 1 )
178                 goto killaudio;
179
180         /* This is an even number of bytes long */
181         if( dlb_fread( name, (iffhead.namelen+1) & ~1, 1, stream ) != 1 )
182                 goto killaudio;
183
184         if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 )
185                 goto killaudio;
186
187         if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 )
188                 goto killaudio;
189
190         waveptr = AllocMem( samples, MEMF_CHIP|MEMF_PUBLIC );
191         if( !waveptr )
192                 goto killaudio;
193
194         if( dlb_fread( waveptr, samples, 1, stream ) != 1 )
195                 goto killaudio;
196
197         while( melody[0] && melody[1] )
198         {
199                 c = *melody++;
200                 duration = *melody++;
201                 dot = 0;
202                 if( *melody == '.' )
203                 {
204                         dot = 1;
205                         ++melody;
206                 }
207                 switch( duration )
208                 {
209                         case 'w': dlay = 3; duration = 1; cycles = 1; break;
210                         case 'h': dlay = 3; duration = 2; cycles = 1; break;
211                         case 'q': dlay = 2; duration = 4; cycles = 1; break;
212                         case 'e': dlay = 1; duration = 8; cycles = 1; break;
213                         case 'x': dlay = 0; duration = 16; cycles = 1; break;
214                         case 't': dlay = 0; duration = 32; cycles = 1; break;
215                         default: goto killaudio;  /* unrecognized duration */
216                 }
217
218                 /* Lower case characters are one octave above upper case */
219                 switch( c )
220                 {
221                         case 'a': case 'b': case 'c':
222                         case 'd': case 'e': case 'f': case 'g':
223                                 c -= 'a' - 7;
224                                 break;
225
226                         case 'A': case 'B': case 'C':
227                         case 'D': case 'E': case 'F': case 'G':
228                                 c -= 'A';
229                                 break;
230
231                         default:
232                                 continue;
233                 }
234
235                 samcyc = samples;
236
237                 /* lowercase start at middle 'C', upper case are one octave below */
238                 frequency = c > 7 ? freqtab[notetab[c%7]]*2 : freqtab[notetab[c]];
239
240                 /* We can't actually do a dotted whole note unless we add code for a real
241                  * 8SVX sample which includes sustain sample information to tell us how
242                  * to hold the note steady...  So when duration == 1, ignore 'dot'...
243                  */
244                 if( dot && duration > 1 )
245                         samp = ((samples / duration) * 3) / 2;
246                 else
247                         samp = samples / duration;
248
249                 /* Only use some of the samples based on frequency */
250                 samp = frequency * samp / 880;
251
252                 /* The 22khz samples are middle C samples, so adjust the play
253                  * back frequency accordingly
254                  */
255                 frequency = (frequency * (iffhead.vhdr.freq*2)/3) / 440L;
256
257                 AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
258                 AudioIO->ioa_Request.io_Command = CMD_WRITE;
259                 AudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
260                 AudioIO->ioa_Data = (BYTE *)waveptr;
261                 AudioIO->ioa_Length = samp;
262
263                 /* The clock rate represents the unity rate, so dividing by
264                  * the frequency gives us a period ratio...
265                  */
266 /*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency, clock/frequency );*/
267                 AudioIO->ioa_Period = clock/frequency;
268                 AudioIO->ioa_Volume = vol;
269                 AudioIO->ioa_Cycles = cycles;
270
271                 BeginIO( (struct IORequest *)AudioIO );
272                 WaitPort( AudioMP );
273                 AudioMSG = GetMsg( AudioMP );
274                 if( dlay )
275                         Delay( dlay );
276         }
277
278         killaudio:
279         if( stream ) dlb_fclose( stream );
280         if( waveptr ) FreeMem( waveptr, samples );
281         if( device == 0 ) CloseDevice( (struct IORequest *)AudioIO );
282         if( AudioMP ) DeleteMsgPort( AudioMP );
283         if( AudioIO ) FreeMem( AudioIO, sizeof( *AudioIO ) );
284 }