NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / sys / amiga / amisnd.c
blobf2418eb2d424fe5302b328d00e04afff9726365a
1 /* aNetHack 0.0.1 amisnd.c $ANH-Date: 1432512796 2015/05/25 00:13:16 $ $ANH-Branch: master $:$ANH-Revision: 1.7 $ */
2 /* Copyright (c) 1992, 1993, 1995 by Gregg Wonderly */
3 /* aNetHack may be freely redistributed. See license for details. */
5 /*
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...
12 #include "hack.h"
13 #include "dlb.h"
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>
26 #include <proto/exec.h>
27 #include <clib/alib_protos.h>
28 #include <proto/dos.h>
29 #include <proto/graphics.h>
31 #include <stdio.h>
32 #include <stdlib.h>
34 #define AMII_AVERAGE_VOLUME 60
36 int amii_volume = AMII_AVERAGE_VOLUME;
38 typedef struct VHDR {
39 char name[4];
40 long len;
41 unsigned long oneshot, repeat, samples;
42 UWORD freq;
43 UBYTE n_octaves, compress;
44 LONG volume;
45 } VHDR;
47 typedef struct IFFHEAD {
48 char FORM[4];
49 long flen;
50 char _8SVX[4];
51 VHDR vhdr;
52 char NAME[4];
53 long namelen;
54 } 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' */
66 long freqtab[] = {
67 220, /*A */
68 233, /*Bb*/
69 246, /*B */
70 261, /*C */
71 277, /*Db*/
72 293, /*D */
73 311, /*Eb*/
74 329, /*E */
75 349, /*F */
76 370, /*Gb*/
77 392, /*G */
78 415, /*Ab*/
79 440, /*A */
82 #ifdef TESTING
83 main(argc, argv) int argc;
84 char **argv;
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);
101 #else
102 void
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);
115 #endif
117 void
118 makesound(char *actualn, char *melody, int vol)
120 char *t;
121 int c, cycles, dot, dlay;
122 dlb *stream = 0;
123 IFFHEAD iffhead;
124 struct IOAudio *AudioIO = 0;
125 struct MsgPort *AudioMP = 0;
126 struct Message *AudioMSG = 0;
127 ULONG device = -1;
128 BYTE *waveptr = 0;
129 LONG frequency = 440, duration = 1, clock, samp, samples, samcyc = 1;
130 unsigned char name[100];
132 if (flags.silent)
133 return;
135 if (GfxBase->DisplayFlags & PAL)
136 clock = 3546895;
137 else
138 clock = 3579545;
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, ' '))
146 *t = '_';
147 if ((stream = dlb_fopen(name, "r")) == NULL) {
148 perror(name);
149 return;
152 AudioIO = (struct IOAudio *) AllocMem(sizeof(struct IOAudio),
153 MEMF_PUBLIC | MEMF_CLEAR);
154 if (AudioIO == 0)
155 goto killaudio;
157 AudioMP = CreateMsgPort();
158 if (AudioMP == 0)
159 goto killaudio;
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);
170 if (device != 0)
171 goto killaudio;
173 if (dlb_fread((genericptr_t) &iffhead, sizeof(iffhead), 1, stream) != 1)
174 goto killaudio;
176 /* This is an even number of bytes long */
177 if (dlb_fread(name, (iffhead.namelen + 1) & ~1, 1, stream) != 1)
178 goto killaudio;
180 if (dlb_fread((genericptr_t) &samples, 4, 1, stream) != 1)
181 goto killaudio;
183 if (dlb_fread((genericptr_t) &samples, 4, 1, stream) != 1)
184 goto killaudio;
186 waveptr = AllocMem(samples, MEMF_CHIP | MEMF_PUBLIC);
187 if (!waveptr)
188 goto killaudio;
190 if (dlb_fread(waveptr, samples, 1, stream) != 1)
191 goto killaudio;
193 while (melody[0] && melody[1]) {
194 c = *melody++;
195 duration = *melody++;
196 dot = 0;
197 if (*melody == '.') {
198 dot = 1;
199 ++melody;
201 switch (duration) {
202 case 'w':
203 dlay = 3;
204 duration = 1;
205 cycles = 1;
206 break;
207 case 'h':
208 dlay = 3;
209 duration = 2;
210 cycles = 1;
211 break;
212 case 'q':
213 dlay = 2;
214 duration = 4;
215 cycles = 1;
216 break;
217 case 'e':
218 dlay = 1;
219 duration = 8;
220 cycles = 1;
221 break;
222 case 'x':
223 dlay = 0;
224 duration = 16;
225 cycles = 1;
226 break;
227 case 't':
228 dlay = 0;
229 duration = 32;
230 cycles = 1;
231 break;
232 default:
233 goto killaudio; /* unrecognized duration */
236 /* Lower case characters are one octave above upper case */
237 switch (c) {
238 case 'a':
239 case 'b':
240 case 'c':
241 case 'd':
242 case 'e':
243 case 'f':
244 case 'g':
245 c -= 'a' - 7;
246 break;
248 case 'A':
249 case 'B':
250 case 'C':
251 case 'D':
252 case 'E':
253 case 'F':
254 case 'G':
255 c -= 'A';
256 break;
258 default:
259 continue;
262 samcyc = samples;
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
268 * real
269 * 8SVX sample which includes sustain sample information to tell us
270 * how
271 * to hold the note steady... So when duration == 1, ignore 'dot'...
273 if (dot && duration > 1)
274 samp = ((samples / duration) * 3) / 2;
275 else
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);
302 WaitPort(AudioMP);
303 AudioMSG = GetMsg(AudioMP);
304 if (dlay)
305 Delay(dlay);
308 killaudio:
309 if (stream)
310 dlb_fclose(stream);
311 if (waveptr)
312 FreeMem(waveptr, samples);
313 if (device == 0)
314 CloseDevice((struct IORequest *) AudioIO);
315 if (AudioMP)
316 DeleteMsgPort(AudioMP);
317 if (AudioIO)
318 FreeMem(AudioIO, sizeof(*AudioIO));