|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.