|
|
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 "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 1.1.1.5 ! root 38: struct MsgPort *AHImp=NULL; 1.1.1.2 root 39: struct AHIRequest *AHIio[2]={NULL,NULL}; 40: struct AHIRequest *linkio=NULL; 41: 1.1.1.5 ! root 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 1.1.1.2 root 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.1.5 ! root 95: #define CIAAPRA 0xBFE001 1.1 root 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()) ) { 1.1.1.5 ! root 146: if( (AHIio[0]=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) ) { 1.1.1.2 root 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) { 1.1.1.5 ! root 184: AbortIO((struct IORequest *) AHIio[0]); ! 185: WaitIO((struct IORequest *) AHIio[0]); 1.1.1.2 root 186: } 187: if(linkio) { /* Only if the second request was started */ 1.1.1.5 ! root 188: AbortIO((struct IORequest *) AHIio[1]); ! 189: WaitIO((struct IORequest *) AHIio[1]); 1.1.1.2 root 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.1.5 ! root 201: int init_sound (void) 1.1 root 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 */ 1.1.1.5 ! root 209: 1.1 root 210: /* determine the clock */ 1.1.1.5 ! root 211: { 1.1 root 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)) { 1.1.1.5 ! root 224: fprintf(stderr, "Sound buffer size %d out of range.\n", currprefs.sound_maxbsiz); ! 225: currprefs.sound_maxbsiz = 8192; ! 226: } 1.1 root 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); 1.1.1.5 ! root 233: currprefs.sound_freq = 22000; 1.1 root 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"), 1.1.1.5 ! root 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", 1.1.1.5 ! root 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", 1.1.1.5 ! root 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", 1.1.1.5 ! root 254: rate, sndbufsize); ! 255: 1.1.1.2 root 256: if(!AUDIO_FILE && !ahiopen) { 1.1.1.5 ! root 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; ! 269: if(OpenDevice(devname = AUDIONAME, 0, (void*)AudioIO, 0)) goto fail; ! 270: devopen = 1; 1.1.1.2 root 271: } 1.1 root 272: 273: /* get the buffers */ 274: if(AUDIO_FILE) { 1.1.1.5 ! root 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 ) { 1.1.1.5 ! root 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; 1.1.1.2 root 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: #endif /* !AHI_DMA_MODE && ! FRAME_RATE_HACK */ 1.1 root 307: } else { 1.1.1.5 ! root 308: buffers[0] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR); ! 309: buffers[1] = (void*)AllocMem(sndbufsize,MEMF_CHIP|MEMF_CLEAR); ! 310: if(!buffers[0] || !buffers[1]) goto fail; 1.1 root 311: } 312: bufidx = 0; 313: sndbuffer = sndbufpt = (uae_u16*)buffers[bufidx]; 314: 315: oldledstate = cia->ciapra & (1<<CIAB_LED); 316: cia->ciapra |= (1<<CIAB_LED); 317: 1.1.1.3 root 318: scaled_sample_evtime = (unsigned long)maxhpos * maxvpos * vblank_hz * CYCLE_UNIT / rate; 319: scaled_sample_evtime_ok = 1; 320: 321: if (ahiopen) { 1.1.1.5 ! root 322: if(currprefs.sound_bits == 16) { 1.1.1.2 root 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 { 1.1.1.5 ! root 332: currprefs.stereo = 0; 1.1.1.2 root 333: init_sound_table8 (); 1.1.1.5 ! root 334: sample_handler = sample8_handler; 1.1.1.2 root 335: } 1.1 root 336: 1.1.1.2 root 337: fprintf(stderr, "Sound driver found and configured for %d bits %s " 1.1.1.5 ! root 338: "at %d Hz, buffer is %d bytes (%s)\n", ! 339: currprefs.sound_bits,(currprefs.stereo==1 ? "stereo" : "mono"), 1.1.1.2 root 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) { 1.1.1.5 ! root 392: cia->ciapra = (cia->ciapra & ~(1<<CIAB_LED)) | oldledstate; 1.1 root 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.