diff --git a/sys/amiga/amisnd.c b/sys/amiga/amisnd.c new file mode 100644 index 000000000..85a007d94 --- /dev/null +++ b/sys/amiga/amisnd.c @@ -0,0 +1,284 @@ +/* SCCS Id: @(#)amisnd.c 3.2 2000/01/12*/ +/* Copyright (c) 1992, 1993, 1995 by Gregg Wonderly */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * This file contains music playing code. + * + * If we were REALLY determined, we would make the sound play + * asynchronously, but I'll save that one for a rainy day... + */ + +#include "hack.h" +#include "dlb.h" + +#undef red +#undef blue +#undef green +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define AMII_AVERAGE_VOLUME 60 + +int amii_volume = AMII_AVERAGE_VOLUME; + +typedef struct VHDR +{ + char name[4]; + long len; + unsigned long oneshot, repeat, samples; + UWORD freq; + UBYTE n_octaves, compress; + LONG volume; +} VHDR; + +typedef struct IFFHEAD +{ + char FORM[4]; + long flen; + char _8SVX[4]; + VHDR vhdr; + char NAME[4]; + long namelen; +} IFFHEAD; + +extern struct GfxBase *GfxBase; + +UBYTE whichannel[] = { 1, 2, 4, 8 }; +void makesound( char *, char *, int vol); +void amii_speaker( struct obj *instr, char *melody, int vol ); + +/* A major scale in indexs to freqtab... */ +int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 }; + +/* Frequencies for a scale starting at one octave below 'middle C' */ +long freqtab[] = { + 220, /*A */ + 233, /*Bb*/ + 246, /*B */ + 261, /*C */ + 277, /*Db*/ + 293, /*D */ + 311, /*Eb*/ + 329, /*E */ + 349, /*F */ + 370, /*Gb*/ + 392, /*G */ + 415, /*Ab*/ + 440, /*A */ +}; + +#ifdef TESTING +main( argc, argv ) + int argc; + char **argv; +{ + makesound( "wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60 ); + makesound( "wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60 ); + makesound( "wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60 ); + makesound( "wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60 ); + makesound( "wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); + makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); +} +#else +void +amii_speaker( struct obj *instr, char *melody, int vol ) +{ + int typ = instr->otyp; + char * actualn = (char *)OBJ_NAME( objects[typ] ) ; + + /* Make volume be relative to users volume level, with 60 being the + * average level that will be passed to us. + */ + vol = vol * amii_volume / AMII_AVERAGE_VOLUME; + + makesound( actualn, melody, vol ); +} +#endif + +void +makesound ( char *actualn , char * melody, int vol ) +{ + char *t; + int c, cycles, dot, dlay; + dlb *stream = 0; + IFFHEAD iffhead; + struct IOAudio *AudioIO = 0; + struct MsgPort *AudioMP = 0; + struct Message *AudioMSG = 0; + ULONG device = -1; + BYTE *waveptr = 0; + LONG frequency=440, duration=1, clock, samp, samples, samcyc=1; + unsigned char name [ 100 ] ; + + if ( flags.silent ) + return; + + if( GfxBase->DisplayFlags & PAL ) + clock = 3546895; + else + clock = 3579545; + + /* + * Convert type to file name - if there's nothing to play we + * shouldn't be here in the first place. + */ + strncpy(name, actualn,sizeof(name) ) ; + for( t = strchr( name, ' ' ); t; t = strchr( name, ' ' ) ) + *t = '_'; + if( (stream = dlb_fopen( name, "r" )) == NULL ) + { + perror( name ); + return; + } + + AudioIO = (struct IOAudio *) + AllocMem( sizeof( struct IOAudio ), MEMF_PUBLIC|MEMF_CLEAR ); + if( AudioIO == 0 ) + goto killaudio; + + AudioMP = CreateMsgPort(); + if( AudioMP == 0 ) + goto killaudio; + + AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP; + AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0; + AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE; + AudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT; + AudioIO->ioa_AllocKey = 0; + AudioIO->ioa_Data = whichannel; + AudioIO->ioa_Length = sizeof( whichannel ); + + device = OpenDevice( AUDIONAME, 0L, (struct IORequest *)AudioIO, 0L ); + if( device != 0 ) + goto killaudio; + + if( dlb_fread( (genericptr_t)&iffhead, sizeof( iffhead ), 1, stream ) != 1 ) + goto killaudio; + + /* This is an even number of bytes long */ + if( dlb_fread( name, (iffhead.namelen+1) & ~1, 1, stream ) != 1 ) + goto killaudio; + + if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 ) + goto killaudio; + + if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 ) + goto killaudio; + + waveptr = AllocMem( samples, MEMF_CHIP|MEMF_PUBLIC ); + if( !waveptr ) + goto killaudio; + + if( dlb_fread( waveptr, samples, 1, stream ) != 1 ) + goto killaudio; + + while( melody[0] && melody[1] ) + { + c = *melody++; + duration = *melody++; + dot = 0; + if( *melody == '.' ) + { + dot = 1; + ++melody; + } + switch( duration ) + { + case 'w': dlay = 3; duration = 1; cycles = 1; break; + case 'h': dlay = 3; duration = 2; cycles = 1; break; + case 'q': dlay = 2; duration = 4; cycles = 1; break; + case 'e': dlay = 1; duration = 8; cycles = 1; break; + case 'x': dlay = 0; duration = 16; cycles = 1; break; + case 't': dlay = 0; duration = 32; cycles = 1; break; + default: goto killaudio; /* unrecognized duration */ + } + + /* Lower case characters are one octave above upper case */ + switch( c ) + { + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': case 'g': + c -= 'a' - 7; + break; + + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': case 'G': + c -= 'A'; + break; + + default: + continue; + } + + samcyc = samples; + + /* lowercase start at middle 'C', upper case are one octave below */ + frequency = c > 7 ? freqtab[notetab[c%7]]*2 : freqtab[notetab[c]]; + + /* We can't actually do a dotted whole note unless we add code for a real + * 8SVX sample which includes sustain sample information to tell us how + * to hold the note steady... So when duration == 1, ignore 'dot'... + */ + if( dot && duration > 1 ) + samp = ((samples / duration) * 3) / 2; + else + samp = samples / duration; + + /* Only use some of the samples based on frequency */ + samp = frequency * samp / 880; + + /* The 22khz samples are middle C samples, so adjust the play + * back frequency accordingly + */ + frequency = (frequency * (iffhead.vhdr.freq*2)/3) / 440L; + + AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP; + AudioIO->ioa_Request.io_Command = CMD_WRITE; + AudioIO->ioa_Request.io_Flags = ADIOF_PERVOL; + AudioIO->ioa_Data = (BYTE *)waveptr; + AudioIO->ioa_Length = samp; + + /* The clock rate represents the unity rate, so dividing by + * the frequency gives us a period ratio... + */ +/*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency, clock/frequency );*/ + AudioIO->ioa_Period = clock/frequency; + AudioIO->ioa_Volume = vol; + AudioIO->ioa_Cycles = cycles; + + BeginIO( (struct IORequest *)AudioIO ); + WaitPort( AudioMP ); + AudioMSG = GetMsg( AudioMP ); + if( dlay ) + Delay( dlay ); + } + + killaudio: + if( stream ) dlb_fclose( stream ); + if( waveptr ) FreeMem( waveptr, samples ); + if( device == 0 ) CloseDevice( (struct IORequest *)AudioIO ); + if( AudioMP ) DeleteMsgPort( AudioMP ); + if( AudioIO ) FreeMem( AudioIO, sizeof( *AudioIO ) ); +}