|
|
1.1.1.5 root 1: /*
1.1 root 2: * UAE - The Un*x Amiga Emulator
1.1.1.5 root 3: *
1.1 root 4: * Support for Amiga audio.device sound
1.1.1.5 root 5: *
1.1.1.2 root 6: * Copyright 1996, 1997, 1998 Samuel Devulder, Holger Jakob (AHI).
7: *
8: * History:
9: * 22/02/98: Added AHI support from Holger Jakob.
10: * 05/04/98: Added AHI_DMA_MODE from Holger Jakob.
1.1 root 11: */
12:
13: #include "sysconfig.h"
14: #include "sysdeps.h"
15:
16: #include "options.h"
17: #include "memory.h"
1.1.1.3 root 18: #include "events.h"
1.1 root 19: #include "custom.h"
20: #include "audio.h"
21: #include "gensound.h"
22: #include "sounddep/sound.h"
23:
24: #include <hardware/custom.h>
25: #include <hardware/cia.h>
26:
1.1.1.2 root 27: #if defined(POWERUP)
28: #include <clib/alib_protos.h>
29: #include <dos/dosextens.h>
30: #undef AllocMem
31: #undef FreeMem
32: #define AllocMem PPCAllocMem
33: #define FreeMem PPCFreeMem
34: #endif
35:
36: #ifdef USE_AHIDEVICE
1.1.1.5 root 37: struct MsgPort *AHImp=NULL;
1.1.1.2 root 38: struct AHIRequest *AHIio[2]={NULL,NULL};
39: struct AHIRequest *linkio=NULL;
40:
1.1.1.5 root 41: /* sam: AHI_DMA_MODE come from Holger Jakob. In this mode, uae
42: will output the sound in real time. It is to be used in conjunction
1.1.1.2 root 43: with FRAME_RATE_HACK. Use this on fast hardwares only! */
44: #ifdef AHI_DMA_MODE
45: #ifndef USE_CLIB
46: #include <powerup/ppcproto/ahi.h>
47: #else /* USE_CLIB */
48: #define AHI_AudioRequest(a0, tags...) \
49: ({ULONG _tags[] = { tags }; AHI_AudioRequestA((a0), (struct TagItem *)_tags);})
50:
51: #define AHI_ControlAudio(a0, tags...) \
52: ({ULONG _tags[] = { tags }; AHI_ControlAudioA((a0), (struct TagItem *)_tags);})
53:
54: #define AHI_AllocAudio(tags...) \
55: ({ULONG _tags[] = { tags }; AHI_AllocAudioA((struct TagItem *)_tags);})
56:
57: #define AHI_AllocAudioRequest(tags...) \
58: ({ULONG _tags[] = { tags }; AHI_AllocAudioRequestA((struct TagItem *)_tags);})
59: #endif /* USE_CLIB */
60:
61: #include <utility/hooks.h>
62: struct Library *AHIBase=NULL;
63: struct AHIAudioCtrl *actrl=NULL;
64: struct AHIEffect {
65: struct AHIEffChannelInfo eff;
66: ULONG Offset[2];
67: } effect = {0};
68: struct AHISampleInfo Sample0 =
69: {
70: AHIST_M8S,
71: NULL,
72: NULL,
73: };
74: uae_u16 *sndbufptrmax=NULL;
75:
76: #if defined(POWERUP)
77: unsigned short dummyfunc[]={0x4E75,0x4E75}; /* rts */
78: #else /* not POWERUP => plain old mc68k */
79: long __saveds dummyfunc(void);
80: __asm("
81: .text
82: .globl _dummyfunc
83: _dummyfunc:
84: rts
85: ");
86: #endif /* POWERUP */
87: struct Hook hook = { 0, 0, (void *)dummyfunc, NULL, NULL };
88:
89: static unsigned long basevsynctime;
90: signed long bufsamples;
91: #endif /* AHI_DMA_MODE */
92: #endif /* AHI_DEVICE */
93:
1.1.1.5 root 94: #define CIAAPRA 0xBFE001
1.1 root 95: #define CUSTOM 0xDFF000
96:
97: static struct Custom *custom= (struct Custom*) CUSTOM;
98: static struct CIA *cia = (struct CIA *) CIAAPRA;
99:
100: /*
101: * Compared to Linux, AF_SOUND, and mac above, the AMIGA sound processing
102: * with OS routines is awfull. (sam). But with AHI DOSDriver it is far more
1.1.1.2 root 103: * easier (but it is still a mess here !).
1.1 root 104: */
105:
106: char whichchannel[]={1,2,4,8};
1.1.1.2 root 107: struct IOAudio *AudioIO=NULL;
108: struct MsgPort *AudioMP=NULL;
109: struct Message *AudioMSG=NULL;
1.1 root 110:
111: unsigned char *buffers[2];
112: uae_u16 *sndbuffer;
113: uae_u16 *sndbufpt;
114: int sndbufsize;
1.1.1.2 root 115: int bufidx, devopen,ahiopen;
1.1 root 116:
117: int have_sound, clockval, oldledstate, period;
118:
119: ULONG AUDIO_FILE;
120:
121: static ULONG TST_AUDIO_FILE(char *buff, char *name, int rate, int bsize)
122: {
123: struct Process *pr = (void*)FindTask(NULL);
124: ULONG wd, fd;
125:
126: if(!name) return 0;
127: wd = (ULONG)pr->pr_WindowPtr;
128: pr->pr_WindowPtr = (APTR)-1;
129: sprintf(buff,name,rate,bsize);
130: fd = Open(buff, MODE_NEWFILE);
131: pr->pr_WindowPtr = (APTR)wd;
132: return fd;
133: }
134:
135: int setup_sound(void)
136: {
137: sound_available = 1;
138: return 1;
139: }
140:
1.1.1.2 root 141: static char* open_AHI(void)
142: {
143: #ifdef USE_AHIDEVICE
144: if( (AHImp=CreateMsgPort()) ) {
1.1.1.5 root 145: if( (AHIio[0]=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) ) {
1.1.1.2 root 146: AHIio[0]->ahir_Version=4;
147: #ifdef AHI_DMA_MODE
148: if( !OpenDevice(AHINAME,AHI_NO_UNIT,(struct IORequest *)AHIio[0],NULL) ) {
149: #else
150: if( !OpenDevice(AHINAME,0,(struct IORequest *)AHIio[0],NULL) ) {
151: #endif
152: if( (AHIio[1] = malloc(sizeof(struct AHIRequest))) ) {
153: #ifdef AHI_DMA_MODE
154: AHIBase=(struct Library *)AHIio[0]->ahir_Std.io_Device;
155: actrl=(struct AHIAudioCtrl *)AHI_AllocAudio(
156: AHIA_AudioID,0x00020008,
157: AHIA_MixFreq,11025,
158: AHIA_Channels,1,
159: AHIA_Sounds,1,
160: TAG_DONE);
161: #endif
162: memcpy(AHIio[1], AHIio[0], sizeof(struct AHIRequest));
163: ahiopen = 1;
164: return AHINAME;
165: }}}}
166: #endif
167: ahiopen = 0;
168: return NULL;
169: }
170:
171: static void close_AHI(void)
172: {
173: #ifdef USE_AHIDEVICE
174: if( ahiopen ) {
175: #ifdef AHI_DMA_MODE
176: if(actrl) {
177: effect.eff.ahie_Effect=AHIET_CHANNELINFO | AHIET_CANCEL;
178: AHI_SetEffect(&effect,actrl);
179: AHI_FreeAudio(actrl); actrl==NULL;
180: }
181: #endif
182: if(AHIio[0]->ahir_Std.io_Length) {
1.1.1.5 root 183: AbortIO((struct IORequest *) AHIio[0]);
184: WaitIO((struct IORequest *) AHIio[0]);
1.1.1.2 root 185: }
186: if(linkio) { /* Only if the second request was started */
1.1.1.5 root 187: AbortIO((struct IORequest *) AHIio[1]);
188: WaitIO((struct IORequest *) AHIio[1]);
1.1.1.2 root 189: }
190: CloseDevice((struct IORequest *)AHIio[0]);
191: DeleteIORequest((void*)AHIio[0]);
192: if(AHImp) DeleteMsgPort((void*)AHImp);
193: AHIio[0]=NULL;
194: AHIio[1]=NULL;
195: ahiopen = 0;
196: }
197: #endif
198: }
199:
1.1.1.5 root 200: int init_sound (void)
1.1 root 201: { /* too complex ? No it is only the allocation of a single channel ! */
202: /* it would have been far less painfull if AmigaOS provided a */
203: /* SOUND: device handler */
204: int rate;
205: char buff[256],*devname = NULL;
206:
207: atexit(close_sound); /* if only amiga os had resource tracking */
1.1.1.5 root 208:
1.1 root 209: /* determine the clock */
1.1.1.5 root 210: {
1.1 root 211: struct GfxBase *GB;
212: GB = (void*)OpenLibrary("graphics.library",0L);
213: if(!GB) goto fail;
214: if (GB->DisplayFlags & PAL)
215: clockval = 3546895; /* PAL clock */
216: else
217: clockval = 3579545; /* NTSC clock */
218: CloseLibrary((void*)GB);
219: }
220:
221: /* check buffsize */
222: if (currprefs.sound_maxbsiz < 2 || currprefs.sound_maxbsiz > (256*1024)) {
1.1.1.5 root 223: fprintf(stderr, "Sound buffer size %d out of range.\n", currprefs.sound_maxbsiz);
224: currprefs.sound_maxbsiz = 8192;
225: }
1.1 root 226: sndbufsize = (currprefs.sound_maxbsiz + 1)&~1;
227:
228: /* check freq */
229: if (!currprefs.sound_freq) currprefs.sound_freq = 1;
1.1.1.2 root 230: if (clockval/currprefs.sound_freq < 80/*124*/ || clockval/currprefs.sound_freq > 65535) {
1.1 root 231: fprintf(stderr, "Can't use sound with desired frequency %d Hz\n", currprefs.sound_freq);
1.1.1.5 root 232: currprefs.sound_freq = 22000;
1.1 root 233: }
234: rate = currprefs.sound_freq;
235: period = (uae_u16)(clockval/rate);
236:
1.1.1.2 root 237: /* check for $AUDIONAME */
1.1 root 238: devname = buff;
239: AUDIO_FILE = TST_AUDIO_FILE(buff, getenv("AUDIONAME"),
1.1.1.5 root 240: rate, sndbufsize);
1.1.1.2 root 241:
242: if(!AUDIO_FILE) {char *s=open_AHI();if(s) devname=s;}
243:
244: if(!AUDIO_FILE && !ahiopen) /* AHI dos-handler */
1.1 root 245: AUDIO_FILE = TST_AUDIO_FILE(buff, "AUDIO:FREQUENCY=%d/BUFFER=%d",
1.1.1.5 root 246: rate, sndbufsize);
1.1.1.2 root 247: /* check for AUD: or AUDIO: device */
248: if(!AUDIO_FILE && !ahiopen) /* AUDIO: */
1.1 root 249: AUDIO_FILE = TST_AUDIO_FILE(buff, "AUDIO:FREQUENCY%d/BUFFER%d",
1.1.1.5 root 250: rate, sndbufsize);
1.1.1.2 root 251: if(!AUDIO_FILE && !ahiopen) /* AUD: */
1.1 root 252: AUDIO_FILE = TST_AUDIO_FILE(buff, "AUD:FREQUENCY%d/BUFFER%d",
1.1.1.5 root 253: rate, sndbufsize);
254:
1.1.1.2 root 255: if(!AUDIO_FILE && !ahiopen) {
1.1.1.5 root 256: /* else use the plain old audio.device */
257: /* setup the stuff */
258: AudioMP = CreateMsgPort();
259: if(!AudioMP) goto fail;
260: AudioIO = (struct IOAudio *)CreateIORequest(AudioMP,
261: sizeof(struct IOAudio));
262: if(!AudioIO) goto fail;
263:
264: AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri /*pfew!!*/ = 85;
265: AudioIO->ioa_Data = whichchannel;
266: AudioIO->ioa_Length = sizeof(whichchannel);
267: AudioIO->ioa_AllocKey = 0;
268: if(OpenDevice(devname = AUDIONAME, 0, (void*)AudioIO, 0)) goto fail;
269: devopen = 1;
1.1.1.2 root 270: }
1.1 root 271:
272: /* get the buffers */
273: if(AUDIO_FILE) {
1.1.1.5 root 274: buffers[0] = (void*)AllocMem(sndbufsize,MEMF_ANY|MEMF_CLEAR);
275: buffers[1] = NULL;
276: if(!buffers[0]) goto fail;
1.1.1.2 root 277: } else if( ahiopen ) {
1.1.1.5 root 278: buffers[0] = (void*)AllocMem(sndbufsize,MEMF_PUBLIC|MEMF_CLEAR);
279: buffers[1] = (void*)AllocMem(sndbufsize,MEMF_PUBLIC|MEMF_CLEAR);
280: if(!buffers[0] || !buffers[1]) goto fail;
1.1.1.2 root 281:
282: #ifdef AHI_DMA_MODE
283: sndbufptrmax = (uae_u16 *)(((uae_u8 *)buffers[0]) + sndbufsize);
284: basevsynctime = vsynctime;
285:
286: if(currprefs.sound_bits == 16)
287: Sample0.ahisi_Type=(currprefs.stereo==1)?AHIST_S16S:AHIST_M16S;
288: else
289: Sample0.ahisi_Type=(currprefs.stereo==1)?AHIST_S8S:AHIST_M8S;
290: Sample0.ahisi_Length=sndbufsize/((currprefs.stereo?2:1)*(currprefs.sound_bits==16?2:1));
291: Sample0.ahisi_Address=buffers[0];
292: AHI_LoadSound(0,AHIST_SAMPLE,&Sample0,actrl);
293:
294: AHI_SetFreq(0,rate,actrl,AHISF_IMM);
295: AHI_SetVol(0,0x10000L,0x08000L,actrl,AHISF_IMM);
296: AHI_SetSound(0,0,0,0,actrl,AHISF_IMM);
297: AHI_ControlAudio(actrl, AHIC_Play,TRUE, TAG_DONE);
298:
299: effect.eff.ahie_Effect=AHIET_CHANNELINFO;
300: effect.eff.ahieci_Func=&hook;
301: effect.eff.ahieci_Channels=1;
302: effect.eff.ahieci_Pad=0;
303:
304: AHI_SetEffect(&effect,actrl);
305: #endif /* !AHI_DMA_MODE && ! FRAME_RATE_HACK */
1.1 root 306: } else {
1.1.1.5 root 307: buffers[0] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR);
308: buffers[1] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR);
309: if(!buffers[0] || !buffers[1]) goto fail;
1.1 root 310: }
311: bufidx = 0;
312: sndbuffer = sndbufpt = (uae_u16*)buffers[bufidx];
313:
314: oldledstate = cia->ciapra & (1<<CIAB_LED);
315: cia->ciapra |= (1<<CIAB_LED);
316:
1.1.1.3 root 317: scaled_sample_evtime = (unsigned long)maxhpos * maxvpos * vblank_hz * CYCLE_UNIT / rate;
318: scaled_sample_evtime_ok = 1;
319:
320: if (ahiopen) {
1.1.1.5 root 321: if(currprefs.sound_bits == 16) {
1.1.1.2 root 322: init_sound_table16 ();
323: sample_handler = currprefs.stereo ? sample16s_handler
324: : sample16_handler;
325: } else {
326: init_sound_table8 ();
327: sample_handler = currprefs.stereo ? sample8s_handler
328: : sample8_handler;
329: }
330: } else {
1.1.1.5 root 331: currprefs.stereo = 0;
1.1.1.2 root 332: init_sound_table8 ();
1.1.1.5 root 333: sample_handler = sample8_handler;
1.1.1.2 root 334: }
1.1 root 335:
1.1.1.2 root 336: fprintf(stderr, "Sound driver found and configured for %d bits %s "
1.1.1.5 root 337: "at %d Hz, buffer is %d bytes (%s)\n",
338: currprefs.sound_bits,(currprefs.stereo==1 ? "stereo" : "mono"),
1.1.1.2 root 339: rate, sndbufsize,devname);
1.1 root 340:
341: sound_available = 1;
342: return 1;
343: fail:
344: sound_available = 0;
345: return 0;
346: }
347:
1.1.1.2 root 348: void adjust_sound_timing (void)
349: {
350: #ifdef AHI_DMA_MODE
351: static unsigned long last;
352: signed long diff;
353: unsigned long samplepos;
354:
355: samplepos = (unsigned long)(effect.Offset[0]*(1));
356: bufsamples=sndbufsize/2;
357:
358: if (!samplepos)
359: samplepos++;
360:
361: if (last == samplepos)
362: return;
363: last = samplepos;
364:
365: /* diff = samplecount - samplepos;*/
366: diff = (int)((uae_u8 *)sndbufpt-buffers[0]) - samplepos;
367: diff-=1024;
368:
369:
370: /* if (diff < -bufsamples || diff > bufsamples) {
371: sndbufpt = (uae_u16 *)buffers[0];
372: }*/
373: if (diff < -bufsamples) diff+=sndbufsize; else if (diff > bufsamples) diff-=sndbufsize;
374: if (diff < 0)
375: vsynctime = basevsynctime * 5 / 6;
376: else if (diff > 0)
377: vsynctime = basevsynctime * 7 / 6;
378: #endif
379: }
380:
1.1 root 381: void close_sound(void)
382: {
1.1.1.2 root 383: if(ahiopen) {close_AHI();ahiopen = 0;}
384: if(AUDIO_FILE) {Close(AUDIO_FILE);AUDIO_FILE=NULL;}
1.1 root 385: if(devopen) {CloseDevice((void*)AudioIO);devopen = 0;}
1.1.1.2 root 386: if(AudioIO) {DeleteIORequest((void*)AudioIO);AudioIO = NULL;}
387: if(AudioMP) {DeleteMsgPort((void*)AudioMP);AudioMP = NULL;}
1.1 root 388: if(buffers[0]) {FreeMem((APTR)buffers[0],sndbufsize);buffers[0] = 0;}
389: if(buffers[1]) {FreeMem((APTR)buffers[1],sndbufsize);buffers[1] = 0;}
390: if(sound_available) {
1.1.1.5 root 391: cia->ciapra = (cia->ciapra & ~(1<<CIAB_LED)) | oldledstate;
1.1 root 392: sound_available = 0;
393: }
394: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.