1 /* NetHack 3.6 amisnd.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */
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
;
41 unsigned long oneshot
, repeat
, samples
;
43 UBYTE n_octaves
, compress
;
47 typedef struct IFFHEAD
{
56 extern struct GfxBase
*GfxBase
;
58 UBYTE whichannel
[] = { 1, 2, 4, 8 };
59 void makesound(char *, char *, int vol
);
60 void amii_speaker(struct obj
*instr
, char *melody
, int vol
);
62 /* A major scale in indexs to freqtab... */
63 int notetab
[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
65 /* Frequencies for a scale starting at one octave below 'middle C' */
83 main(argc
, argv
) int argc
;
86 makesound("wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60);
87 makesound("wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60);
88 makesound("wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60);
89 makesound("wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60);
90 makesound("wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60);
91 makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60);
92 makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60);
93 makesound("wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 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);
103 amii_speaker(struct obj
*instr
, char *melody
, int vol
)
105 int typ
= instr
->otyp
;
106 char *actualn
= (char *) OBJ_NAME(objects
[typ
]);
108 /* Make volume be relative to users volume level, with 60 being the
109 * average level that will be passed to us.
111 vol
= vol
* amii_volume
/ AMII_AVERAGE_VOLUME
;
113 makesound(actualn
, melody
, vol
);
118 makesound(char *actualn
, char *melody
, int vol
)
121 int c
, cycles
, dot
, dlay
;
124 struct IOAudio
*AudioIO
= 0;
125 struct MsgPort
*AudioMP
= 0;
126 struct Message
*AudioMSG
= 0;
129 LONG frequency
= 440, duration
= 1, clock
, samp
, samples
, samcyc
= 1;
130 unsigned char name
[100];
135 if (GfxBase
->DisplayFlags
& PAL
)
141 * Convert type to file name - if there's nothing to play we
142 * shouldn't be here in the first place.
144 strncpy(name
, actualn
, sizeof(name
));
145 for (t
= strchr(name
, ' '); t
; t
= strchr(name
, ' '))
147 if ((stream
= dlb_fopen(name
, "r")) == NULL
) {
152 AudioIO
= (struct IOAudio
*) AllocMem(sizeof(struct IOAudio
),
153 MEMF_PUBLIC
| MEMF_CLEAR
);
157 AudioMP
= CreateMsgPort();
161 AudioIO
->ioa_Request
.io_Message
.mn_ReplyPort
= AudioMP
;
162 AudioIO
->ioa_Request
.io_Message
.mn_Node
.ln_Pri
= 0;
163 AudioIO
->ioa_Request
.io_Command
= ADCMD_ALLOCATE
;
164 AudioIO
->ioa_Request
.io_Flags
= ADIOF_NOWAIT
;
165 AudioIO
->ioa_AllocKey
= 0;
166 AudioIO
->ioa_Data
= whichannel
;
167 AudioIO
->ioa_Length
= sizeof(whichannel
);
169 device
= OpenDevice(AUDIONAME
, 0L, (struct IORequest
*) AudioIO
, 0L);
173 if (dlb_fread((genericptr_t
) &iffhead
, sizeof(iffhead
), 1, stream
) != 1)
176 /* This is an even number of bytes long */
177 if (dlb_fread(name
, (iffhead
.namelen
+ 1) & ~1, 1, stream
) != 1)
180 if (dlb_fread((genericptr_t
) &samples
, 4, 1, stream
) != 1)
183 if (dlb_fread((genericptr_t
) &samples
, 4, 1, stream
) != 1)
186 waveptr
= AllocMem(samples
, MEMF_CHIP
| MEMF_PUBLIC
);
190 if (dlb_fread(waveptr
, samples
, 1, stream
) != 1)
193 while (melody
[0] && melody
[1]) {
195 duration
= *melody
++;
197 if (*melody
== '.') {
233 goto killaudio
; /* unrecognized duration */
236 /* Lower case characters are one octave above upper case */
264 /* lowercase start at middle 'C', upper case are one octave below */
265 frequency
= c
> 7 ? freqtab
[notetab
[c
% 7]] * 2 : freqtab
[notetab
[c
]];
267 /* We can't actually do a dotted whole note unless we add code for a
269 * 8SVX sample which includes sustain sample information to tell us
271 * to hold the note steady... So when duration == 1, ignore 'dot'...
273 if (dot
&& duration
> 1)
274 samp
= ((samples
/ duration
) * 3) / 2;
276 samp
= samples
/ duration
;
278 /* Only use some of the samples based on frequency */
279 samp
= frequency
* samp
/ 880;
281 /* The 22khz samples are middle C samples, so adjust the play
282 * back frequency accordingly
284 frequency
= (frequency
* (iffhead
.vhdr
.freq
* 2) / 3) / 440L;
286 AudioIO
->ioa_Request
.io_Message
.mn_ReplyPort
= AudioMP
;
287 AudioIO
->ioa_Request
.io_Command
= CMD_WRITE
;
288 AudioIO
->ioa_Request
.io_Flags
= ADIOF_PERVOL
;
289 AudioIO
->ioa_Data
= (BYTE
*) waveptr
;
290 AudioIO
->ioa_Length
= samp
;
292 /* The clock rate represents the unity rate, so dividing by
293 * the frequency gives us a period ratio...
295 /*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency,
296 * clock/frequency );*/
297 AudioIO
->ioa_Period
= clock
/ frequency
;
298 AudioIO
->ioa_Volume
= vol
;
299 AudioIO
->ioa_Cycles
= cycles
;
301 BeginIO((struct IORequest
*) AudioIO
);
303 AudioMSG
= GetMsg(AudioMP
);
312 FreeMem(waveptr
, samples
);
314 CloseDevice((struct IORequest
*) AudioIO
);
316 DeleteMsgPort(AudioMP
);
318 FreeMem(AudioIO
, sizeof(*AudioIO
));