|
|
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: int sound_available = 0; ! 40: ! 41: struct audio_channel_data audio_channel[4]; ! 42: ! 43: int sound_table[64][256]; ! 44: unsigned long int sample_evtime; ! 45: ! 46: void init_sound_table16(void) ! 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: void AUDxDAT(int nr, uae_u16 v) ! 65: { ! 66: struct audio_channel_data *cdp = audio_channel + nr; ! 67: cdp->dat = v; ! 68: if (cdp->state == 0 && !(INTREQR() & (0x80 << nr))) { ! 69: cdp->state = 2; ! 70: INTREQ(0x8000 | (0x80 << nr)); ! 71: /* data_written = 2 ???? */ ! 72: eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; ! 73: eventtab[ev_aud0 + nr].oldcycles = cycles; ! 74: eventtab[ev_aud0 + nr].active = 1; ! 75: events_schedule(); ! 76: } ! 77: } ! 78: ! 79: void AUDxLCH(int nr, uae_u16 v) { audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((uae_u32)v << 16); } ! 80: void AUDxLCL(int nr, uae_u16 v) { audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); } ! 81: void AUDxPER(int nr, uae_u16 v) ! 82: { ! 83: if (v <= 0) { ! 84: #if 0 /* v == 0 is rather common, and harmless, and the value isn't signed anyway */ ! 85: static int warned = 0; ! 86: if (!warned) ! 87: write_log ("Broken program accessing the sound hardware\n"), warned++; ! 88: #endif ! 89: v = 65535; ! 90: } ! 91: if (v < maxhpos/2 && currprefs.produce_sound < 3) ! 92: v = maxhpos/2; ! 93: ! 94: audio_channel[nr].per = v; ! 95: } ! 96: ! 97: void AUDxLEN(int nr, uae_u16 v) { audio_channel[nr].len = v; } ! 98: ! 99: #define MULTIPLICATION_PROFITABLE ! 100: ! 101: #ifdef MULTIPLICATION_PROFITABLE ! 102: typedef uae_s8 sample8_t; ! 103: #define DO_CHANNEL_1(v, c) do { (v) *= audio_channel[c].vol; } while (0) ! 104: #define SBASEVAL8(logn) ((logn) == 1 ? SOUND8_BASE_VAL << 7 : SOUND8_BASE_VAL << 8) ! 105: #define SBASEVAL16(logn) ((logn) == 1 ? SOUND16_BASE_VAL >> 1 : SOUND16_BASE_VAL) ! 106: #define FINISH_DATA(b,logn) do { if (14 - (b) + (logn) > 0) data >>= 14 - (b) + (logn); else data <<= (b) - 14 - (logn); } while (0); ! 107: #else ! 108: typedef uae_u8 sample8_t; ! 109: #define DO_CHANNEL_1(v, c) do { (v) = audio_channel[c].voltbl[(v)]; } while (0) ! 110: #define SBASEVAL8(logn) SOUND8_BASE_VAL ! 111: #define SBASEVAL16(logn) SOUND16_BASE_VAL ! 112: #define FINISH_DATA(b,logn) ! 113: #endif ! 114: ! 115: void AUDxVOL(int nr, uae_u16 v) ! 116: { ! 117: int v2 = v & 64 ? 63 : v & 63; ! 118: audio_channel[nr].vol = v2; ! 119: #ifndef MULTIPLICATION_PROFITABLE ! 120: audio_channel[nr].voltbl = sound_table[v2]; ! 121: #endif ! 122: } ! 123: ! 124: #define DO_CHANNEL(v, c) do { (v) &= audio_channel[c].adk_mask; data += v; } while (0); ! 125: ! 126: /* Templates! I want templates! */ ! 127: void sample16_handler(void) ! 128: { ! 129: BEGIN_BENCH ! 130: ! 131: uae_u32 data0 = audio_channel[0].current_sample; ! 132: uae_u32 data1 = audio_channel[1].current_sample; ! 133: uae_u32 data2 = audio_channel[2].current_sample; ! 134: uae_u32 data3 = audio_channel[3].current_sample; ! 135: DO_CHANNEL_1 (data0, 0); ! 136: DO_CHANNEL_1 (data1, 1); ! 137: DO_CHANNEL_1 (data2, 2); ! 138: DO_CHANNEL_1 (data3, 3); ! 139: data0 &= audio_channel[0].adk_mask; ! 140: data1 &= audio_channel[1].adk_mask; ! 141: data2 &= audio_channel[2].adk_mask; ! 142: data3 &= audio_channel[3].adk_mask; ! 143: data0 += data1; ! 144: data0 += data2; ! 145: data0 += data3; ! 146: { ! 147: uae_u32 data = SBASEVAL16(2) + data0; ! 148: FINISH_DATA(16, 2); ! 149: PUT_SOUND_WORD (data); ! 150: } ! 151: END_BENCH ! 152: ! 153: check_sound_buffers (); ! 154: ! 155: eventtab[ev_sample].evtime = cycles + sample_evtime; ! 156: eventtab[ev_sample].oldcycles = cycles; ! 157: } ! 158: ! 159: void sample8_handler(void) ! 160: { ! 161: BEGIN_BENCH ! 162: ! 163: uae_u32 data0 = audio_channel[0].current_sample; ! 164: uae_u32 data1 = audio_channel[1].current_sample; ! 165: uae_u32 data2 = audio_channel[2].current_sample; ! 166: uae_u32 data3 = audio_channel[3].current_sample; ! 167: DO_CHANNEL_1 (data0, 0); ! 168: DO_CHANNEL_1 (data1, 1); ! 169: DO_CHANNEL_1 (data2, 2); ! 170: DO_CHANNEL_1 (data3, 3); ! 171: data0 &= audio_channel[0].adk_mask; ! 172: data1 &= audio_channel[1].adk_mask; ! 173: data2 &= audio_channel[2].adk_mask; ! 174: data3 &= audio_channel[3].adk_mask; ! 175: data0 += data1; ! 176: data0 += data2; ! 177: data0 += data3; ! 178: { ! 179: uae_u32 data = SBASEVAL8(2) + data0; ! 180: FINISH_DATA(8, 2); ! 181: PUT_SOUND_BYTE (data); ! 182: } ! 183: END_BENCH ! 184: ! 185: check_sound_buffers (); ! 186: ! 187: eventtab[ev_sample].evtime = cycles + sample_evtime; ! 188: eventtab[ev_sample].oldcycles = cycles; ! 189: } ! 190: ! 191: #ifdef HAVE_STEREO_SUPPORT ! 192: void sample16s_handler(void) ! 193: { ! 194: BEGIN_BENCH ! 195: ! 196: uae_u32 data0 = audio_channel[0].current_sample; ! 197: uae_u32 data1 = audio_channel[1].current_sample; ! 198: uae_u32 data2 = audio_channel[2].current_sample; ! 199: uae_u32 data3 = audio_channel[3].current_sample; ! 200: DO_CHANNEL_1 (data0, 0); ! 201: DO_CHANNEL_1 (data1, 1); ! 202: DO_CHANNEL_1 (data2, 2); ! 203: DO_CHANNEL_1 (data3, 3); ! 204: ! 205: data0 &= audio_channel[0].adk_mask; ! 206: data1 &= audio_channel[1].adk_mask; ! 207: data2 &= audio_channel[2].adk_mask; ! 208: data3 &= audio_channel[3].adk_mask; ! 209: ! 210: data0 += data3; ! 211: { ! 212: uae_u32 data = SBASEVAL16(1) + data0; ! 213: FINISH_DATA (16, 1); ! 214: PUT_SOUND_WORD_RIGHT (data); ! 215: } ! 216: ! 217: data1 += data2; ! 218: { ! 219: uae_u32 data = SBASEVAL16(1) + data1; ! 220: FINISH_DATA (16, 1); ! 221: PUT_SOUND_WORD_LEFT (data); ! 222: } ! 223: ! 224: END_BENCH ! 225: ! 226: check_sound_buffers (); ! 227: ! 228: eventtab[ev_sample].evtime = cycles + sample_evtime; ! 229: eventtab[ev_sample].oldcycles = cycles; ! 230: } ! 231: ! 232: void sample8s_handler(void) ! 233: { ! 234: BEGIN_BENCH ! 235: ! 236: uae_u32 data0 = audio_channel[0].current_sample; ! 237: uae_u32 data1 = audio_channel[1].current_sample; ! 238: uae_u32 data2 = audio_channel[2].current_sample; ! 239: uae_u32 data3 = audio_channel[3].current_sample; ! 240: DO_CHANNEL_1 (data0, 0); ! 241: DO_CHANNEL_1 (data1, 1); ! 242: DO_CHANNEL_1 (data2, 2); ! 243: DO_CHANNEL_1 (data3, 3); ! 244: ! 245: data0 &= audio_channel[0].adk_mask; ! 246: data1 &= audio_channel[1].adk_mask; ! 247: data2 &= audio_channel[2].adk_mask; ! 248: data3 &= audio_channel[3].adk_mask; ! 249: ! 250: data0 += data3; ! 251: { ! 252: uae_u32 data = SBASEVAL8(1) + data0; ! 253: FINISH_DATA (8, 1); ! 254: PUT_SOUND_BYTE_RIGHT (data); ! 255: } ! 256: data1 += data2; ! 257: { ! 258: uae_u32 data = SBASEVAL8(1) + data1; ! 259: FINISH_DATA (8, 1); ! 260: PUT_SOUND_BYTE_LEFT (data); ! 261: } ! 262: ! 263: END_BENCH ! 264: ! 265: check_sound_buffers (); ! 266: ! 267: eventtab[ev_sample].evtime = cycles + sample_evtime; ! 268: eventtab[ev_sample].oldcycles = cycles; ! 269: } ! 270: #else ! 271: void sample8s_handler(void) ! 272: { ! 273: sample8_handler(); ! 274: } ! 275: void sample16s_handler(void) ! 276: { ! 277: sample16_handler(); ! 278: } ! 279: #endif ! 280: ! 281: static uae_u8 int2ulaw(int ch) ! 282: { ! 283: int mask; ! 284: ! 285: if (ch < 0) { ! 286: ch = -ch; ! 287: mask = 0x7f; ! 288: } ! 289: else { ! 290: mask = 0xff; ! 291: } ! 292: ! 293: if (ch < 32) { ! 294: ch = 0xF0 | ( 15 - (ch/2) ); ! 295: } else if (ch < 96) { ! 296: ch = 0xE0 | ( 15 - (ch-32)/4 ); ! 297: } else if (ch < 224) { ! 298: ch = 0xD0 | ( 15 - (ch-96)/8 ); ! 299: } else if (ch < 480) { ! 300: ch = 0xC0 | ( 15 - (ch-224)/16 ); ! 301: } else if (ch < 992 ) { ! 302: ch = 0xB0 | ( 15 - (ch-480)/32 ); ! 303: } else if (ch < 2016) { ! 304: ch = 0xA0 | ( 15 - (ch-992)/64 ); ! 305: } else if (ch < 4064) { ! 306: ch = 0x90 | ( 15 - (ch-2016)/128 ); ! 307: } else if (ch < 8160) { ! 308: ch = 0x80 | ( 15 - (ch-4064)/256 ); ! 309: } else { ! 310: ch = 0x80; ! 311: } ! 312: return (uae_u8)(mask & ch); ! 313: } ! 314: ! 315: void sample_ulaw_handler (void) ! 316: { ! 317: int nr; ! 318: uae_u32 data = 0; ! 319: ! 320: eventtab[ev_sample].evtime += cycles - eventtab[ev_sample].oldcycles; ! 321: eventtab[ev_sample].oldcycles = cycles; ! 322: ! 323: for (nr = 0; nr < 4; nr++) { ! 324: if (!(adkcon & (0x11 << nr))) { ! 325: uae_u32 d = audio_channel[nr].current_sample; ! 326: DO_CHANNEL_1 (d, nr); ! 327: data += d; ! 328: } ! 329: } ! 330: PUT_SOUND_BYTE (int2ulaw (data)); ! 331: check_sound_buffers (); ! 332: } ! 333: ! 334: static void audio_handler (int nr) ! 335: { ! 336: struct audio_channel_data *cdp = audio_channel + nr; ! 337: ! 338: switch (cdp->state) { ! 339: case 0: ! 340: fprintf(stderr, "Bug in sound code\n"); ! 341: break; ! 342: ! 343: case 1: ! 344: /* We come here at the first hsync after DMA was turned on. */ ! 345: eventtab[ev_aud0 + nr].evtime += maxhpos; ! 346: eventtab[ev_aud0 + nr].oldcycles += maxhpos; ! 347: ! 348: cdp->state = 5; ! 349: INTREQ(0x8000 | (0x80 << nr)); ! 350: if (cdp->wlen != 1) ! 351: cdp->wlen--; ! 352: cdp->nextdat = chipmem_bank.wget(cdp->pt); ! 353: ! 354: cdp->pt += 2; ! 355: break; ! 356: ! 357: case 5: ! 358: /* We come here at the second hsync after DMA was turned on. */ ! 359: if (currprefs.produce_sound == 0) ! 360: cdp->per = 65535; ! 361: ! 362: eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; ! 363: eventtab[ev_aud0 + nr].oldcycles = cycles; ! 364: cdp->dat = cdp->nextdat; ! 365: cdp->current_sample = (sample8_t)(cdp->dat >> 8); ! 366: ! 367: cdp->state = 2; ! 368: { ! 369: int audav = adkcon & (1 << nr); ! 370: int audap = adkcon & (16 << nr); ! 371: int napnav = (!audav && !audap) || audav; ! 372: if (napnav) ! 373: cdp->data_written = 2; ! 374: } ! 375: break; ! 376: ! 377: case 2: ! 378: /* We come here when a 2->3 transition occurs */ ! 379: if (currprefs.produce_sound == 0) ! 380: cdp->per = 65535; ! 381: ! 382: cdp->current_sample = (sample8_t)(cdp->dat & 0xFF); ! 383: eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; ! 384: eventtab[ev_aud0 + nr].oldcycles = cycles; ! 385: ! 386: cdp->state = 3; ! 387: ! 388: /* Period attachment? */ ! 389: if (adkcon & (0x10 << nr)) { ! 390: if (cdp->intreq2 && cdp->dmaen) ! 391: INTREQ(0x8000 | (0x80 << nr)); ! 392: cdp->intreq2 = 0; ! 393: ! 394: cdp->dat = cdp->nextdat; ! 395: if (cdp->dmaen) ! 396: cdp->data_written = 2; ! 397: if (nr < 3) { ! 398: if (cdp->dat == 0) ! 399: (cdp+1)->per = 65535; ! 400: ! 401: else if (cdp->dat < maxhpos/2 && currprefs.produce_sound < 3) ! 402: (cdp+1)->per = maxhpos/2; ! 403: else ! 404: (cdp+1)->per = cdp->dat; ! 405: } ! 406: } ! 407: break; ! 408: ! 409: case 3: ! 410: /* We come here when a 3->2 transition occurs */ ! 411: if (currprefs.produce_sound == 0) ! 412: cdp->per = 65535; ! 413: ! 414: eventtab[ev_aud0 + nr].evtime = cycles + cdp->per; ! 415: eventtab[ev_aud0 + nr].oldcycles = cycles; ! 416: ! 417: if ((INTREQR() & (0x80 << nr)) && !cdp->dmaen) { ! 418: cdp->state = 0; ! 419: cdp->current_sample = 0; ! 420: eventtab[ev_aud0 + nr].active = 0; ! 421: break; ! 422: } else { ! 423: int audav = adkcon & (1 << nr); ! 424: int audap = adkcon & (16 << nr); ! 425: int napnav = (!audav && !audap) || audav; ! 426: cdp->state = 2; ! 427: ! 428: if ((cdp->intreq2 && cdp->dmaen && napnav) ! 429: || (napnav && !cdp->dmaen)) ! 430: INTREQ(0x8000 | (0x80 << nr)); ! 431: cdp->intreq2 = 0; ! 432: ! 433: cdp->dat = cdp->nextdat; ! 434: cdp->current_sample = (sample8_t)(cdp->dat >> 8); ! 435: ! 436: if (cdp->dmaen && napnav) ! 437: cdp->data_written = 2; ! 438: ! 439: /* Volume attachment? */ ! 440: if (audav) { ! 441: if (nr < 3) { ! 442: (cdp+1)->vol = cdp->dat; ! 443: #ifndef MULTIPLICATION_PROFITABLE ! 444: (cdp+1)->voltbl = sound_table[cdp->dat]; ! 445: #endif ! 446: } ! 447: } ! 448: } ! 449: break; ! 450: ! 451: default: ! 452: cdp->state = 0; ! 453: eventtab[ev_aud0 + nr].active = 0; ! 454: break; ! 455: } ! 456: } ! 457: ! 458: void aud0_handler (void) ! 459: { ! 460: audio_handler (0); ! 461: } ! 462: void aud1_handler (void) ! 463: { ! 464: audio_handler (1); ! 465: } ! 466: void aud2_handler (void) ! 467: { ! 468: audio_handler (2); ! 469: } ! 470: void aud3_handler (void) ! 471: { ! 472: audio_handler (3); ! 473: } ! 474: ! 475: void audio_reset (void) ! 476: { ! 477: memset (audio_channel, 0, sizeof audio_channel); ! 478: audio_channel[0].per = 65535; ! 479: audio_channel[1].per = 65535; ! 480: audio_channel[2].per = 65535; ! 481: audio_channel[3].per = 65535; ! 482: audio_channel[0].voltbl = sound_table[0]; ! 483: audio_channel[1].voltbl = sound_table[0]; ! 484: audio_channel[2].voltbl = sound_table[0]; ! 485: audio_channel[3].voltbl = sound_table[0]; ! 486: } ! 487: ! 488: void dump_audio_bench (void) ! 489: { ! 490: #ifdef BENCHMARK_AUDIO ! 491: printf ("Average cycles per sample handler: %f\n", ((double)sh_time / sh_count)); ! 492: #endif ! 493: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.