|
|
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"
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
! 37: struct MsgPort *AHImp=NULL;
! 38: struct AHIRequest *AHIio[2]={NULL,NULL};
! 39: struct AHIRequest *linkio=NULL;
! 40:
! 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
! 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 root 94: #define CIAAPRA 0xBFE001
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()) ) {
! 145: if( (AHIio[0]=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) ) {
! 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) {
! 183: AbortIO((struct IORequest *) AHIio[0]);
! 184: WaitIO((struct IORequest *) AHIio[0]);
! 185: }
! 186: if(linkio) { /* Only if the second request was started */
! 187: AbortIO((struct IORequest *) AHIio[1]);
! 188: WaitIO((struct IORequest *) AHIio[1]);
! 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 root 200: int init_sound (void)
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 */
208:
209: /* determine the clock */
210: {
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)) {
223: fprintf(stderr, "Sound buffer size %d out of range.\n", currprefs.sound_maxbsiz);
224: currprefs.sound_maxbsiz = 8192;
225: }
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);
232: currprefs.sound_freq = 22000;
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"),
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",
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",
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",
253: rate, sndbufsize);
1.1.1.2 ! root 254:
! 255: if(!AUDIO_FILE && !ahiopen) {
! 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;
1.1 root 268: if(OpenDevice(devname = AUDIONAME, 0, (void*)AudioIO, 0)) goto fail;
1.1.1.2 ! root 269: devopen = 1;
! 270: }
1.1 root 271:
272: /* get the buffers */
273: if(AUDIO_FILE) {
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 ) {
! 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;
! 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: #elif defined(FRAME_RATE_HACK)
! 306: /* reduce vsynctime a bit to give the sound emulation more room to breathe.*/
! 307: vsynctime = vsynctime * 9 / 10;
! 308: #endif /* !AHI_DMA_MODE && ! FRAME_RATE_HACK */
1.1 root 309: } else {
310: buffers[0] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR);
311: buffers[1] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR);
312: if(!buffers[0] || !buffers[1]) goto fail;
313: }
314: bufidx = 0;
315: sndbuffer = sndbufpt = (uae_u16*)buffers[bufidx];
316:
317: oldledstate = cia->ciapra & (1<<CIAB_LED);
318: cia->ciapra |= (1<<CIAB_LED);
319:
320: sample_evtime = (long)maxhpos * maxvpos * 50 / rate;
1.1.1.2 ! root 321: if (ahiopen) {
! 322: if(currprefs.sound_bits == 16) {
! 323: init_sound_table16 ();
! 324: sample_handler = currprefs.stereo ? sample16s_handler
! 325: : sample16_handler;
! 326: } else {
! 327: init_sound_table8 ();
! 328: sample_handler = currprefs.stereo ? sample8s_handler
! 329: : sample8_handler;
! 330: }
! 331: } else {
! 332: currprefs.stereo = 0;
! 333: init_sound_table8 ();
! 334: sample_handler = sample8_handler;
! 335: }
1.1 root 336:
1.1.1.2 ! root 337: fprintf(stderr, "Sound driver found and configured for %d bits %s "
1.1 root 338: "at %d Hz, buffer is %d bytes (%s)\n",
1.1.1.2 ! root 339: currprefs.sound_bits,(currprefs.stereo==1 ? "stereo" : "mono"),
! 340: rate, sndbufsize,devname);
1.1 root 341:
342: sound_available = 1;
343: return 1;
344: fail:
345: sound_available = 0;
346: return 0;
347: }
348:
1.1.1.2 ! root 349: void adjust_sound_timing (void)
! 350: {
! 351: #ifdef AHI_DMA_MODE
! 352: static unsigned long last;
! 353: signed long diff;
! 354: unsigned long samplepos;
! 355:
! 356: samplepos = (unsigned long)(effect.Offset[0]*(1));
! 357: bufsamples=sndbufsize/2;
! 358:
! 359: if (!samplepos)
! 360: samplepos++;
! 361:
! 362: if (last == samplepos)
! 363: return;
! 364: last = samplepos;
! 365:
! 366: /* diff = samplecount - samplepos;*/
! 367: diff = (int)((uae_u8 *)sndbufpt-buffers[0]) - samplepos;
! 368: diff-=1024;
! 369:
! 370:
! 371: /* if (diff < -bufsamples || diff > bufsamples) {
! 372: sndbufpt = (uae_u16 *)buffers[0];
! 373: }*/
! 374: if (diff < -bufsamples) diff+=sndbufsize; else if (diff > bufsamples) diff-=sndbufsize;
! 375: if (diff < 0)
! 376: vsynctime = basevsynctime * 5 / 6;
! 377: else if (diff > 0)
! 378: vsynctime = basevsynctime * 7 / 6;
! 379: #endif
! 380: }
! 381:
1.1 root 382: void close_sound(void)
383: {
1.1.1.2 ! root 384: if(ahiopen) {close_AHI();ahiopen = 0;}
! 385: if(AUDIO_FILE) {Close(AUDIO_FILE);AUDIO_FILE=NULL;}
1.1 root 386: if(devopen) {CloseDevice((void*)AudioIO);devopen = 0;}
1.1.1.2 ! root 387: if(AudioIO) {DeleteIORequest((void*)AudioIO);AudioIO = NULL;}
! 388: if(AudioMP) {DeleteMsgPort((void*)AudioMP);AudioMP = NULL;}
1.1 root 389: if(buffers[0]) {FreeMem((APTR)buffers[0],sndbufsize);buffers[0] = 0;}
390: if(buffers[1]) {FreeMem((APTR)buffers[1],sndbufsize);buffers[1] = 0;}
391: if(sound_available) {
392: cia->ciapra = (cia->ciapra & ~(1<<CIAB_LED)) | oldledstate;
393: sound_available = 0;
394: }
395: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.