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. */
6 * This file contains music playing code.
8 * If we were REALLY determined, we would make the sound play
9 * asynchronously, but I'll save that one for a rainy day...
18 #include <exec/types.h>
19 #include <exec/memory.h>
21 #include <devices/audio.h>
23 #include <dos/dosextens.h>
24 #include <graphics/gfxbase.h>
26 #include <proto/exec.h>
27 #include <clib/alib_protos.h>
28 #include <proto/dos.h>
29 #include <proto/graphics.h>
34 #define AMII_AVERAGE_VOLUME 60
36 int amii_volume = AMII_AVERAGE_VOLUME;
42 unsigned long oneshot, repeat, samples;
44 UBYTE n_octaves, compress;
48 typedef struct IFFHEAD
58 extern struct GfxBase *GfxBase;
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 );
64 /* A major scale in indexs to freqtab... */
65 int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
67 /* Frequencies for a scale starting at one octave below 'middle C' */
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 );
106 amii_speaker( struct obj *instr, char *melody, int vol )
108 int typ = instr->otyp;
109 char * actualn = (char *)OBJ_NAME( objects[typ] ) ;
111 /* Make volume be relative to users volume level, with 60 being the
112 * average level that will be passed to us.
114 vol = vol * amii_volume / AMII_AVERAGE_VOLUME;
116 makesound( actualn, melody, vol );
121 makesound ( char *actualn , char * melody, int vol )
124 int c, cycles, dot, dlay;
127 struct IOAudio *AudioIO = 0;
128 struct MsgPort *AudioMP = 0;
129 struct Message *AudioMSG = 0;
132 LONG frequency=440, duration=1, clock, samp, samples, samcyc=1;
133 unsigned char name [ 100 ] ;
138 if( GfxBase->DisplayFlags & PAL )
144 * Convert type to file name - if there's nothing to play we
145 * shouldn't be here in the first place.
147 strncpy(name, actualn,sizeof(name) ) ;
148 for( t = strchr( name, ' ' ); t; t = strchr( name, ' ' ) )
150 if( (stream = dlb_fopen( name, "r" )) == NULL )
156 AudioIO = (struct IOAudio *)
157 AllocMem( sizeof( struct IOAudio ), MEMF_PUBLIC|MEMF_CLEAR );
161 AudioMP = CreateMsgPort();
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 );
173 device = OpenDevice( AUDIONAME, 0L, (struct IORequest *)AudioIO, 0L );
177 if( dlb_fread( (genericptr_t)&iffhead, sizeof( iffhead ), 1, stream ) != 1 )
180 /* This is an even number of bytes long */
181 if( dlb_fread( name, (iffhead.namelen+1) & ~1, 1, stream ) != 1 )
184 if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 )
187 if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 )
190 waveptr = AllocMem( samples, MEMF_CHIP|MEMF_PUBLIC );
194 if( dlb_fread( waveptr, samples, 1, stream ) != 1 )
197 while( melody[0] && melody[1] )
200 duration = *melody++;
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 */
218 /* Lower case characters are one octave above upper case */
221 case 'a': case 'b': case 'c':
222 case 'd': case 'e': case 'f': case 'g':
226 case 'A': case 'B': case 'C':
227 case 'D': case 'E': case 'F': case 'G':
237 /* lowercase start at middle 'C', upper case are one octave below */
238 frequency = c > 7 ? freqtab[notetab[c%7]]*2 : freqtab[notetab[c]];
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'...
244 if( dot && duration > 1 )
245 samp = ((samples / duration) * 3) / 2;
247 samp = samples / duration;
249 /* Only use some of the samples based on frequency */
250 samp = frequency * samp / 880;
252 /* The 22khz samples are middle C samples, so adjust the play
253 * back frequency accordingly
255 frequency = (frequency * (iffhead.vhdr.freq*2)/3) / 440L;
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;
263 /* The clock rate represents the unity rate, so dividing by
264 * the frequency gives us a period ratio...
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;
271 BeginIO( (struct IORequest *)AudioIO );
273 AudioMSG = GetMsg( AudioMP );
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 ) );