Annotation of uae/src/od-amiga/sound.c, revision 1.1.1.3

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.