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

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

unix.superglobalmegacorp.com

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