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