Annotation of uae/src/audio.c, revision 1.1.1.2

1.1       root        1:  /*
                      2:   * UAE - The Un*x Amiga Emulator
                      3:   *
                      4:   * OS specific functions
                      5:   *
                      6:   * Copyright 1995, 1996, 1997 Bernd Schmidt
                      7:   * Copyright 1996 Marcus Sundberg
                      8:   * Copyright 1996 Manfred Thole
                      9:   */
                     10: 
                     11: #include "sysconfig.h"
                     12: #include "sysdeps.h"
                     13: 
                     14: #include "config.h"
                     15: #include "options.h"
                     16: #include "memory.h"
                     17: #include "custom.h"
                     18: #include "gensound.h"
                     19: #include "sounddep/sound.h"
                     20: #include "events.h"
                     21: #include "audio.h"
                     22: 
                     23: #undef BENCHMARK_AUDIO
                     24: 
                     25: #ifdef BENCHMARK_AUDIO
                     26: 
                     27: #define BEGIN_BENCH frame_time_t audbench = read_processor_time ();
                     28: #define END_BENCH sh_time += read_processor_time () - audbench; sh_count++;
                     29: static frame_time_t sh_time = 0;
                     30: unsigned long sh_count = 0;
                     31: 
                     32: #else
                     33: 
                     34: #define BEGIN_BENCH
                     35: #define END_BENCH
                     36: 
                     37: #endif
                     38: 
                     39: struct audio_channel_data audio_channel[4];
1.1.1.2 ! root       40: int sound_available = 0;
1.1       root       41: int sound_table[64][256];
1.1.1.2 ! root       42: void (*sample_handler) (void);
1.1       root       43: unsigned long int sample_evtime;
1.1.1.2 ! root       44: static unsigned long last_cycles, next_sample_evtime;
1.1       root       45: 
1.1.1.2 ! root       46: void init_sound_table16 (void)
1.1       root       47: {
                     48:     int i,j;
                     49: 
                     50:     for (i = 0; i < 256; i++)
                     51:        for (j = 0; j < 64; j++)
                     52:            sound_table[j][i] = j * (uae_s8)i * (currprefs.stereo ? 2 : 1);
                     53: }
                     54: 
                     55: void init_sound_table8 (void)
                     56: {
                     57:     int i,j;
                     58: 
                     59:     for (i = 0; i < 256; i++)
                     60:        for (j = 0; j < 64; j++)
                     61:            sound_table[j][i] = (j * (uae_s8)i * (currprefs.stereo ? 2 : 1)) / 256;
                     62: }
                     63: 
                     64: #define MULTIPLICATION_PROFITABLE
                     65: 
                     66: #ifdef MULTIPLICATION_PROFITABLE
                     67: typedef uae_s8 sample8_t;
                     68: #define DO_CHANNEL_1(v, c) do { (v) *= audio_channel[c].vol; } while (0)
                     69: #define SBASEVAL8(logn) ((logn) == 1 ? SOUND8_BASE_VAL << 7 : SOUND8_BASE_VAL << 8)
                     70: #define SBASEVAL16(logn) ((logn) == 1 ? SOUND16_BASE_VAL >> 1 : SOUND16_BASE_VAL)
                     71: #define FINISH_DATA(b,logn) do { if (14 - (b) + (logn) > 0) data >>= 14 - (b) + (logn); else data <<= (b) - 14 - (logn); } while (0);
                     72: #else
                     73: typedef uae_u8 sample8_t;
                     74: #define DO_CHANNEL_1(v, c) do { (v) = audio_channel[c].voltbl[(v)]; } while (0)
                     75: #define SBASEVAL8(logn) SOUND8_BASE_VAL
                     76: #define SBASEVAL16(logn) SOUND16_BASE_VAL
                     77: #define FINISH_DATA(b,logn)
                     78: #endif
                     79: 
                     80: #define DO_CHANNEL(v, c) do { (v) &= audio_channel[c].adk_mask; data += v; } while (0);
                     81: 
                     82: /* Templates! I want templates! */
1.1.1.2 ! root       83: void sample16_handler (void)
1.1       root       84: {
                     85:     BEGIN_BENCH
                     86: 
                     87:     uae_u32 data0 = audio_channel[0].current_sample;
                     88:     uae_u32 data1 = audio_channel[1].current_sample;
                     89:     uae_u32 data2 = audio_channel[2].current_sample;
                     90:     uae_u32 data3 = audio_channel[3].current_sample;
                     91:     DO_CHANNEL_1 (data0, 0);
                     92:     DO_CHANNEL_1 (data1, 1);
                     93:     DO_CHANNEL_1 (data2, 2);
                     94:     DO_CHANNEL_1 (data3, 3);
                     95:     data0 &= audio_channel[0].adk_mask;
                     96:     data1 &= audio_channel[1].adk_mask;
                     97:     data2 &= audio_channel[2].adk_mask;
                     98:     data3 &= audio_channel[3].adk_mask;
                     99:     data0 += data1;
                    100:     data0 += data2;
                    101:     data0 += data3;
                    102:     {
                    103:        uae_u32 data = SBASEVAL16(2) + data0;
                    104:        FINISH_DATA(16, 2);
                    105:        PUT_SOUND_WORD (data);
                    106:     }
                    107:     END_BENCH
                    108: 
                    109:     check_sound_buffers ();
                    110: }
                    111: 
1.1.1.2 ! root      112: void sample8_handler (void)
1.1       root      113: {
                    114:     BEGIN_BENCH
                    115:        
                    116:     uae_u32 data0 = audio_channel[0].current_sample;
                    117:     uae_u32 data1 = audio_channel[1].current_sample;
                    118:     uae_u32 data2 = audio_channel[2].current_sample;
                    119:     uae_u32 data3 = audio_channel[3].current_sample;
                    120:     DO_CHANNEL_1 (data0, 0);
                    121:     DO_CHANNEL_1 (data1, 1);
                    122:     DO_CHANNEL_1 (data2, 2);
                    123:     DO_CHANNEL_1 (data3, 3);
                    124:     data0 &= audio_channel[0].adk_mask;
                    125:     data1 &= audio_channel[1].adk_mask;
                    126:     data2 &= audio_channel[2].adk_mask;
                    127:     data3 &= audio_channel[3].adk_mask;
                    128:     data0 += data1;
                    129:     data0 += data2;
                    130:     data0 += data3;
                    131:     {
                    132:        uae_u32 data = SBASEVAL8(2) + data0;
                    133:        FINISH_DATA(8, 2);
                    134:        PUT_SOUND_BYTE (data);
                    135:     }
                    136:     END_BENCH
                    137: 
                    138:     check_sound_buffers ();
                    139: }
                    140: 
                    141: #ifdef HAVE_STEREO_SUPPORT
1.1.1.2 ! root      142: void sample16s_handler (void)
1.1       root      143: {
                    144:     BEGIN_BENCH
                    145: 
                    146:     uae_u32 data0 = audio_channel[0].current_sample;
                    147:     uae_u32 data1 = audio_channel[1].current_sample;
                    148:     uae_u32 data2 = audio_channel[2].current_sample;
                    149:     uae_u32 data3 = audio_channel[3].current_sample;
                    150:     DO_CHANNEL_1 (data0, 0);
                    151:     DO_CHANNEL_1 (data1, 1);
                    152:     DO_CHANNEL_1 (data2, 2);
                    153:     DO_CHANNEL_1 (data3, 3);
                    154: 
                    155:     data0 &= audio_channel[0].adk_mask;
                    156:     data1 &= audio_channel[1].adk_mask;
                    157:     data2 &= audio_channel[2].adk_mask;
                    158:     data3 &= audio_channel[3].adk_mask;
                    159:     
                    160:     data0 += data3;
                    161:     {
                    162:        uae_u32 data = SBASEVAL16(1) + data0;
                    163:        FINISH_DATA (16, 1);
                    164:        PUT_SOUND_WORD_RIGHT (data);
                    165:     }
                    166: 
                    167:     data1 += data2;
                    168:     {
                    169:        uae_u32 data = SBASEVAL16(1) + data1;
                    170:        FINISH_DATA (16, 1);
                    171:        PUT_SOUND_WORD_LEFT (data);
                    172:     }
                    173:     
                    174:     END_BENCH
                    175:     
                    176:     check_sound_buffers ();
                    177: }
                    178: 
1.1.1.2 ! root      179: void sample8s_handler (void)
1.1       root      180: {
                    181:     BEGIN_BENCH
                    182: 
                    183:     uae_u32 data0 = audio_channel[0].current_sample;
                    184:     uae_u32 data1 = audio_channel[1].current_sample;
                    185:     uae_u32 data2 = audio_channel[2].current_sample;
                    186:     uae_u32 data3 = audio_channel[3].current_sample;
                    187:     DO_CHANNEL_1 (data0, 0);
                    188:     DO_CHANNEL_1 (data1, 1);
                    189:     DO_CHANNEL_1 (data2, 2);
                    190:     DO_CHANNEL_1 (data3, 3);
                    191: 
                    192:     data0 &= audio_channel[0].adk_mask;
                    193:     data1 &= audio_channel[1].adk_mask;
                    194:     data2 &= audio_channel[2].adk_mask;
                    195:     data3 &= audio_channel[3].adk_mask;
                    196: 
                    197:     data0 += data3;
                    198:     {
                    199:        uae_u32 data = SBASEVAL8(1) + data0;
                    200:        FINISH_DATA (8, 1);
                    201:        PUT_SOUND_BYTE_RIGHT (data);
                    202:     }
                    203:     data1 += data2;
                    204:     {
                    205:        uae_u32 data = SBASEVAL8(1) + data1;
                    206:        FINISH_DATA (8, 1);
                    207:        PUT_SOUND_BYTE_LEFT (data);
                    208:     }
                    209: 
                    210:     END_BENCH
                    211:     
                    212:     check_sound_buffers ();
                    213: }
                    214: #else
1.1.1.2 ! root      215: void sample8s_handler (void)
1.1       root      216: {
                    217:     sample8_handler();
                    218: }
1.1.1.2 ! root      219: void sample16s_handler (void)
1.1       root      220: {
                    221:     sample16_handler();
                    222: }
                    223: #endif
                    224: 
1.1.1.2 ! root      225: static uae_u8 int2ulaw (int ch)
1.1       root      226: {
                    227:     int mask;
                    228: 
                    229:     if (ch < 0) {
                    230:       ch = -ch;
                    231:       mask = 0x7f;
                    232:     }
                    233:     else {
                    234:       mask = 0xff;
                    235:     }
                    236: 
                    237:     if (ch < 32) {
                    238:        ch = 0xF0 | ( 15 - (ch/2) );
                    239:     } else if (ch < 96) {
                    240:        ch = 0xE0 | ( 15 - (ch-32)/4 );
                    241:     } else if (ch < 224) {
                    242:        ch = 0xD0 | ( 15 - (ch-96)/8 );
                    243:     } else if (ch < 480) {
                    244:        ch = 0xC0 | ( 15 - (ch-224)/16 );
                    245:     } else if (ch < 992 ) {
                    246:        ch = 0xB0 | ( 15 - (ch-480)/32 );
                    247:     } else if (ch < 2016) {
                    248:        ch = 0xA0 | ( 15 - (ch-992)/64 );
                    249:     } else if (ch < 4064) {
                    250:        ch = 0x90 | ( 15 - (ch-2016)/128 );
                    251:     } else if (ch < 8160) {
                    252:        ch = 0x80 | ( 15 - (ch-4064)/256 );
                    253:     } else {
                    254:        ch = 0x80;
                    255:     }
                    256:     return (uae_u8)(mask & ch);
                    257: }
                    258: 
                    259: void sample_ulaw_handler (void)
                    260: {
                    261:     int nr;
                    262:     uae_u32 data = 0;
                    263: 
                    264:     for (nr = 0; nr < 4; nr++) {
                    265:        if (!(adkcon & (0x11 << nr))) {
                    266:            uae_u32 d = audio_channel[nr].current_sample;
                    267:            DO_CHANNEL_1 (d, nr);
                    268:            data += d;
                    269:        }
                    270:     }
                    271:     PUT_SOUND_BYTE (int2ulaw (data));
                    272:     check_sound_buffers ();
                    273: }
                    274: 
                    275: static void audio_handler (int nr)
                    276: {
                    277:     struct audio_channel_data *cdp = audio_channel + nr;
                    278: 
                    279:     switch (cdp->state) {
                    280:      case 0:
                    281:        fprintf(stderr, "Bug in sound code\n");
                    282:        break;
                    283: 
                    284:      case 1:
                    285:        /* We come here at the first hsync after DMA was turned on. */
1.1.1.2 ! root      286:        cdp->evtime = maxhpos;
1.1       root      287: 
                    288:        cdp->state = 5;
                    289:        INTREQ(0x8000 | (0x80 << nr));
                    290:        if (cdp->wlen != 1)
                    291:            cdp->wlen--;
                    292:        cdp->nextdat = chipmem_bank.wget(cdp->pt);
                    293: 
                    294:        cdp->pt += 2;
                    295:        break;
                    296: 
                    297:      case 5:
                    298:        /* We come here at the second hsync after DMA was turned on. */
                    299:        if (currprefs.produce_sound == 0)
                    300:            cdp->per = 65535;
                    301: 
1.1.1.2 ! root      302:        cdp->evtime = cdp->per;
1.1       root      303:        cdp->dat = cdp->nextdat;
                    304:        cdp->current_sample = (sample8_t)(cdp->dat >> 8);
                    305: 
                    306:        cdp->state = 2;
                    307:        {
                    308:            int audav = adkcon & (1 << nr);
                    309:            int audap = adkcon & (16 << nr);
                    310:            int napnav = (!audav && !audap) || audav;
                    311:            if (napnav)
                    312:                cdp->data_written = 2;
                    313:        }
                    314:        break;
                    315: 
                    316:      case 2:
                    317:        /* We come here when a 2->3 transition occurs */
                    318:        if (currprefs.produce_sound == 0)
                    319:            cdp->per = 65535;
                    320: 
                    321:        cdp->current_sample = (sample8_t)(cdp->dat & 0xFF);
1.1.1.2 ! root      322:        cdp->evtime = cdp->per;
1.1       root      323: 
                    324:        cdp->state = 3;
                    325: 
                    326:        /* Period attachment? */
                    327:        if (adkcon & (0x10 << nr)) {
                    328:            if (cdp->intreq2 && cdp->dmaen)
                    329:                INTREQ(0x8000 | (0x80 << nr));
                    330:            cdp->intreq2 = 0;
                    331: 
                    332:            cdp->dat = cdp->nextdat;
                    333:            if (cdp->dmaen)
                    334:                cdp->data_written = 2;
                    335:            if (nr < 3) {
                    336:                if (cdp->dat == 0)
                    337:                    (cdp+1)->per = 65535;
                    338: 
                    339:                else if (cdp->dat < maxhpos/2 && currprefs.produce_sound < 3)
                    340:                    (cdp+1)->per = maxhpos/2;
                    341:                else
                    342:                    (cdp+1)->per = cdp->dat;
                    343:            }
                    344:        }
                    345:        break;
                    346: 
                    347:      case 3:
                    348:        /* We come here when a 3->2 transition occurs */
                    349:        if (currprefs.produce_sound == 0)
                    350:            cdp->per = 65535;
                    351: 
1.1.1.2 ! root      352:        cdp->evtime = cdp->per;
1.1       root      353: 
                    354:        if ((INTREQR() & (0x80 << nr)) && !cdp->dmaen) {
                    355:            cdp->state = 0;
                    356:            cdp->current_sample = 0;
                    357:            break;
                    358:        } else {
                    359:            int audav = adkcon & (1 << nr);
                    360:            int audap = adkcon & (16 << nr);
                    361:            int napnav = (!audav && !audap) || audav;
                    362:            cdp->state = 2;
                    363: 
                    364:            if ((cdp->intreq2 && cdp->dmaen && napnav)
                    365:                || (napnav && !cdp->dmaen))
                    366:                INTREQ(0x8000 | (0x80 << nr));
                    367:            cdp->intreq2 = 0;
                    368: 
                    369:            cdp->dat = cdp->nextdat;
                    370:            cdp->current_sample = (sample8_t)(cdp->dat >> 8);
                    371: 
                    372:            if (cdp->dmaen && napnav)
                    373:                cdp->data_written = 2;
                    374: 
                    375:            /* Volume attachment? */
                    376:            if (audav) {
                    377:                if (nr < 3) {
                    378:                    (cdp+1)->vol = cdp->dat;
                    379: #ifndef MULTIPLICATION_PROFITABLE
                    380:                    (cdp+1)->voltbl = sound_table[cdp->dat];
                    381: #endif
                    382:                }
                    383:            }
                    384:        }
                    385:        break;
                    386: 
                    387:      default:
                    388:        cdp->state = 0;
                    389:        break;
                    390:     }
                    391: }
                    392: 
                    393: void aud0_handler (void)
                    394: {
                    395:     audio_handler (0);
                    396: }
                    397: void aud1_handler (void)
                    398: {
                    399:     audio_handler (1);
                    400: }
                    401: void aud2_handler (void)
                    402: {
                    403:     audio_handler (2);
                    404: }
                    405: void aud3_handler (void)
                    406: {
                    407:     audio_handler (3);
                    408: }
                    409: 
                    410: void audio_reset (void)
                    411: {
                    412:     memset (audio_channel, 0, sizeof audio_channel);
                    413:     audio_channel[0].per = 65535;
                    414:     audio_channel[1].per = 65535;
                    415:     audio_channel[2].per = 65535;
                    416:     audio_channel[3].per = 65535;
                    417:     audio_channel[0].voltbl = sound_table[0];
                    418:     audio_channel[1].voltbl = sound_table[0];
                    419:     audio_channel[2].voltbl = sound_table[0];
                    420:     audio_channel[3].voltbl = sound_table[0];
1.1.1.2 ! root      421: 
        !           422:     last_cycles = 0;
        !           423:     next_sample_evtime = sample_evtime;
        !           424: }
        !           425: 
        !           426: static __inline__ int sound_prefs_changed (void)
        !           427: {
        !           428:     return (changed_prefs.produce_sound != currprefs.produce_sound
        !           429:            || changed_prefs.stereo != currprefs.stereo
        !           430:            || changed_prefs.sound_bits != currprefs.sound_bits);
        !           431: }
        !           432: 
        !           433: void check_prefs_changed_audio (void)
        !           434: {
        !           435:     if (! sound_available || ! sound_prefs_changed ())
        !           436:        return;
        !           437: 
        !           438:     close_sound ();
        !           439:     currprefs.produce_sound = changed_prefs.produce_sound;
        !           440:     currprefs.stereo = changed_prefs.stereo;
        !           441:     currprefs.sound_bits = changed_prefs.sound_bits;
        !           442: 
        !           443:     if (currprefs.produce_sound >= 1) {
        !           444:        if (! init_sound ()) {
        !           445:            if (currprefs.produce_sound == -1) {
        !           446:                fprintf (stderr, "Sound is not supported.\n");
        !           447:            } else {
        !           448:                fprintf (stderr, "Sorry, can't initialize sound.\n");
        !           449:                currprefs.produce_sound = 0;
        !           450:            }
        !           451:        } else {
        !           452:            last_cycles = cycles - 1;
        !           453:            next_sample_evtime = sample_evtime;
        !           454:        }
        !           455:     } else {
        !           456:        printf ("Sound system shut down.\n");
        !           457:     }
        !           458: }
        !           459: 
        !           460: void update_audio (void)
        !           461: {
        !           462:     unsigned long int n_cycles;
        !           463: 
        !           464:     if (currprefs.produce_sound == 0)
        !           465:        return;
        !           466: 
        !           467:     n_cycles = cycles - last_cycles;
        !           468:     for (;;) {
        !           469:        int best = -1;
        !           470:        unsigned long int best_evtime = n_cycles + 1;
        !           471:        if (audio_channel[0].state != 0 && best_evtime > audio_channel[0].evtime)
        !           472:            best = 0, best_evtime = audio_channel[0].evtime;
        !           473:        if (audio_channel[1].state != 0 && best_evtime > audio_channel[1].evtime)
        !           474:            best = 1, best_evtime = audio_channel[1].evtime;
        !           475:        if (audio_channel[2].state != 0 && best_evtime > audio_channel[2].evtime)
        !           476:            best = 2, best_evtime = audio_channel[2].evtime;
        !           477:        if (audio_channel[3].state != 0 && best_evtime > audio_channel[3].evtime)
        !           478:            best = 3, best_evtime = audio_channel[3].evtime;
        !           479:        if (best_evtime > next_sample_evtime)
        !           480:            best_evtime = next_sample_evtime;
        !           481: 
        !           482:        if (best_evtime > n_cycles)
        !           483:            break;
        !           484: 
        !           485:        next_sample_evtime -= best_evtime;
        !           486:        audio_channel[0].evtime -= best_evtime;
        !           487:        audio_channel[1].evtime -= best_evtime;
        !           488:        audio_channel[2].evtime -= best_evtime;
        !           489:        audio_channel[3].evtime -= best_evtime;
        !           490:        n_cycles -= best_evtime;
        !           491:        if (next_sample_evtime == 0) {
        !           492:            next_sample_evtime = sample_evtime;
        !           493:            (*sample_handler) ();
        !           494:        }
        !           495:        if (audio_channel[0].evtime == 0 && audio_channel[0].state != 0)
        !           496:            audio_handler (0);
        !           497:        if (audio_channel[1].evtime == 0 && audio_channel[1].state != 0)
        !           498:            audio_handler (1);
        !           499:        if (audio_channel[2].evtime == 0 && audio_channel[2].state != 0)
        !           500:            audio_handler (2);
        !           501:        if (audio_channel[3].evtime == 0 && audio_channel[3].state != 0)
        !           502:            audio_handler (3);
        !           503:     }
        !           504:     last_cycles = cycles - n_cycles;
        !           505: }
        !           506: 
        !           507: void AUDxDAT (int nr, uae_u16 v)
        !           508: {
        !           509:     struct audio_channel_data *cdp = audio_channel + nr;
        !           510: 
        !           511:     update_audio ();
        !           512: 
        !           513:     cdp->dat = v;
        !           514:     if (cdp->state == 0 && !(INTREQR() & (0x80 << nr))) {
        !           515:        cdp->state = 2;
        !           516:        INTREQ(0x8000 | (0x80 << nr));
        !           517:        /* data_written = 2 ???? */
        !           518:        cdp->evtime = cdp->per;
        !           519:     }
        !           520: }
        !           521: 
        !           522: void AUDxLCH (int nr, uae_u16 v)
        !           523: {
        !           524:     update_audio ();
        !           525: 
        !           526:     audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16);
        !           527: }
        !           528: 
        !           529: void AUDxLCL (int nr, uae_u16 v)
        !           530: {
        !           531:     update_audio ();
        !           532: 
        !           533:     audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE);
        !           534: }
        !           535: 
        !           536: void AUDxPER (int nr, uae_u16 v)
        !           537: {
        !           538:     update_audio ();
        !           539: 
        !           540:     if (v == 0)
        !           541:        v = 65535;
        !           542: 
        !           543:     if (v < maxhpos/2 && currprefs.produce_sound < 3)
        !           544:        v = maxhpos/2;
        !           545: 
        !           546:     audio_channel[nr].per = v;
        !           547: }
        !           548: 
        !           549: void AUDxLEN (int nr, uae_u16 v)
        !           550: {
        !           551:     update_audio ();
        !           552: 
        !           553:     audio_channel[nr].len = v;
        !           554: }
        !           555: 
        !           556: void AUDxVOL (int nr, uae_u16 v)
        !           557: {
        !           558:     int v2 = v & 64 ? 63 : v & 63;
        !           559: 
        !           560:     update_audio ();
        !           561: 
        !           562:     audio_channel[nr].vol = v2;
        !           563: #ifndef MULTIPLICATION_PROFITABLE
        !           564:     audio_channel[nr].voltbl = sound_table[v2];
        !           565: #endif
1.1       root      566: }
                    567: 
                    568: void dump_audio_bench (void)
                    569: {
                    570: #ifdef BENCHMARK_AUDIO
                    571:     printf ("Average cycles per sample handler: %f\n", ((double)sh_time / sh_count));
                    572: #endif
                    573: }

unix.superglobalmegacorp.com

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