1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Toccata Z2 board emulation
5 *
6 * Copyright 2014-2015 Toni Wilen
7 *
8 */
9
10 #include "sysconfig.h"
11 #include "sysdeps.h"
12
13 #include "options.h"
14 #include "uae.h"
15 #include "memory.h"
16 #include "newcpu.h"
17 #include "debug.h"
18 #include "custom.h"
19 #include "sndboard.h"
20 #include "audio.h"
21 #include "autoconf.h"
22 #include "pci_hw.h"
23 #include "qemuvga/qemuaudio.h"
24
25 static uae_u8 *sndboard_get_buffer(int *frames);
26 static void sndboard_release_buffer(uae_u8 *buffer, int frames);
27 static void sndboard_free_capture(void);
28 static bool sndboard_init_capture(int freq);
29
30 static double base_event_clock;
31
32 #define DEBUG_TOCCATA 0
33
34 #define BOARD_MASK 65535
35 #define BOARD_SIZE 65536
36
37 #define FIFO_SIZE 1024
38 #define FIFO_SIZE_HALF (FIFO_SIZE / 2)
39
40 static const uae_u8 toccata_autoconfig[16] = { 0xc1, 12, 0, 0, 18260 >> 8, 18260 & 255 };
41
42 struct toccata_data {
43 uae_u8 acmemory[128];
44 int configured;
45 uae_u8 ad1848_index;
46 uae_u8 ad1848_regs[16];
47 uae_u8 ad1848_status;
48 int autocalibration;
49 uae_u8 toccata_status;
50 int toccata_irq;
51 int fifo_read_index;
52 int fifo_write_index;
53 int data_in_fifo;
54 uae_u8 fifo[FIFO_SIZE];
55
56 int fifo_record_read_index;
57 int fifo_record_write_index;
58 int data_in_record_fifo;
59 uae_u8 record_fifo[FIFO_SIZE];
60
61 int ch_sample[2];
62
63 int fifo_half;
64 int toccata_active;
65 int left_volume, right_volume;
66
67 int freq, freq_adjusted, channels, samplebits;
68 int event_time, record_event_time;
69 int record_event_counter;
70 int bytespersample;
71 };
72
73 static struct toccata_data toccata;
74
75 extern addrbank toccata_bank;
76
77 #define STATUS_ACTIVE 1
78 #define STATUS_RESET 2
79 #define STATUS_FIFO_CODEC 4
80 #define STATUS_FIFO_RECORD 8
81 #define STATUS_FIFO_PLAY 0x10
82 #define STATUS_RECORD_INTENA 0x40
83 #define STATUS_PLAY_INTENA 0x80
84
85 #define STATUS_READ_INTREQ 128
86 #define STATUS_READ_PLAY_HALF 8
87 #define STATUS_READ_RECORD_HALF 4
88
89
update_sndboard_sound(double clk)90 void update_sndboard_sound (double clk)
91 {
92 base_event_clock = clk;
93 }
94
process_fifo(void)95 static void process_fifo(void)
96 {
97 struct toccata_data *data = &toccata;
98 int prev_data_in_fifo = data->data_in_fifo;
99 if (data->data_in_fifo >= data->bytespersample) {
100 uae_s16 v;
101 if (data->samplebits == 8) {
102 v = data->fifo[data->fifo_read_index] << 8;
103 v |= data->fifo[data->fifo_read_index];
104 data->ch_sample[0] = v;
105 if (data->channels == 2) {
106 v = data->fifo[data->fifo_read_index + 1] << 8;
107 v |= data->fifo[data->fifo_read_index + 1];
108 }
109 data->ch_sample[1] = v;
110 } else if (data->samplebits == 16) {
111 v = data->fifo[data->fifo_read_index + 1] << 8;
112 v |= data->fifo[data->fifo_read_index + 0];
113 data->ch_sample[0] = v;
114 if (data->channels == 2) {
115 v = data->fifo[data->fifo_read_index + 3] << 8;
116 v |= data->fifo[data->fifo_read_index + 2];
117 }
118 data->ch_sample[1] = v;
119 }
120 data->data_in_fifo -= data->bytespersample;
121 data->fifo_read_index += data->bytespersample;
122 data->fifo_read_index = data->fifo_read_index % FIFO_SIZE;
123 }
124
125 data->ch_sample[0] = data->ch_sample[0] * data->left_volume / 32768;
126 data->ch_sample[1] = data->ch_sample[1] * data->right_volume / 32768;
127
128 if (data->data_in_fifo < FIFO_SIZE_HALF && prev_data_in_fifo >= FIFO_SIZE_HALF)
129 data->fifo_half |= STATUS_FIFO_PLAY;
130 }
131
audio_state_sndboard_toccata(int ch)132 static void audio_state_sndboard_toccata(int ch)
133 {
134 struct toccata_data *data = &toccata;
135 if ((data->toccata_active & STATUS_FIFO_PLAY) && ch == 0) {
136 // get all bytes at once to prevent fifo going out of sync
137 // if fifo has for example 3 bytes remaining but we need 4.
138 process_fifo();
139 }
140 if (data->toccata_active && (data->toccata_status & STATUS_FIFO_CODEC)) {
141 int old = data->toccata_irq;
142 if ((data->fifo_half & STATUS_FIFO_PLAY) && (data->toccata_status & STATUS_PLAY_INTENA) && (data->toccata_status & STATUS_FIFO_PLAY)) {
143 data->toccata_irq |= STATUS_READ_PLAY_HALF;
144 }
145 if ((data->fifo_half & STATUS_FIFO_RECORD) && (data->toccata_status & STATUS_FIFO_RECORD) && (data->toccata_status & STATUS_FIFO_RECORD)) {
146 data->toccata_irq |= STATUS_READ_RECORD_HALF;
147 }
148 if (old != data->toccata_irq) {
149 sndboard_rethink();
150 #if DEBUG_TOCCATA > 2
151 write_log(_T("TOCCATA IRQ\n"));
152 #endif
153 }
154 }
155 audio_state_sndboard_state(ch, data->ch_sample[ch], data->event_time);
156 }
157
get_volume(uae_u8 v)158 static int get_volume(uae_u8 v)
159 {
160 int out;
161 if (v & 0x80) // Mute bit
162 return 0;
163 out = v & 63;
164 out = 64 - out;
165 out *= 32768 / 64;
166 return out;
167 }
168
get_volume_in(uae_u8 v)169 static int get_volume_in(uae_u8 v)
170 {
171 int out;
172 if (v & 0x80) // Mute bit
173 return 0;
174 out = v & 31;
175 out = 32 - out;
176 out *= 32768 / 32;
177 return out;
178 }
179
calculate_volume_toccata(void)180 static void calculate_volume_toccata(void)
181 {
182 struct toccata_data *data = &toccata;
183 data->left_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
184 data->right_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
185
186 data->left_volume = get_volume(data->ad1848_regs[6]) * data->left_volume / 32768;
187 data->right_volume = get_volume(data->ad1848_regs[7]) * data->right_volume / 32768;
188
189 if (currprefs.sound_toccata_mixer) {
190 sound_paula_volume[0] = get_volume_in(data->ad1848_regs[4]);
191 sound_paula_volume[1] = get_volume_in(data->ad1848_regs[5]);
192
193 sound_cd_volume[0] = get_volume_in(data->ad1848_regs[2]);
194 sound_cd_volume[1] = get_volume_in(data->ad1848_regs[3]);
195 }
196 }
197
198 static const int freq_crystals[] = {
199 // AD1848 documentation says 24.576MHz but photo of board shows 24.582MHz
200 // Added later: It seems there are boards that have correct crystal and
201 // also boards with wrong crystal..
202 // So we can use correct one in emulation.
203 24576000,
204 16934400
205 };
206 static const int freq_dividers[] = {
207 3072,
208 1536,
209 896,
210 768,
211 448,
212 384,
213 512,
214 2560
215 };
216
codec_setup(void)217 static void codec_setup(void)
218 {
219 struct toccata_data *data = &toccata;
220 uae_u8 c = data->ad1848_regs[8];
221
222 data->channels = (c & 0x10) ? 2 : 1;
223 data->samplebits = (c & 0x40) ? 16 : 8;
224 data->freq = freq_crystals[c & 1] / freq_dividers[(c >> 1) & 7];
225 data->freq_adjusted = ((data->freq + 49) / 100) * 100;
226 data->bytespersample = (data->samplebits / 8) * data->channels;
227 write_log(_T("TOCCATA start %s freq=%d bits=%d channels=%d\n"),
228 ((data->toccata_active & (STATUS_FIFO_PLAY | STATUS_FIFO_RECORD)) == (STATUS_FIFO_PLAY | STATUS_FIFO_RECORD)) ? _T("Play+Record") :
229 (data->toccata_active & STATUS_FIFO_PLAY) ? _T("Play") : _T("Record"),
230 data->freq, data->samplebits, data->channels);
231 }
232
233 static int capture_buffer_size = 48000 * 2 * 2; // 1s at 48000/stereo/16bit
234 static int capture_read_index, capture_write_index;
235 static uae_u8 *capture_buffer;
236
codec_start(void)237 static void codec_start(void)
238 {
239 struct toccata_data *data = &toccata;
240 data->toccata_active = (data->ad1848_regs[9] & 1) ? STATUS_FIFO_PLAY : 0;
241 data->toccata_active |= (data->ad1848_regs[9] & 2) ? STATUS_FIFO_RECORD : 0;
242
243 codec_setup();
244
245 data->event_time = base_event_clock * CYCLE_UNIT / data->freq;
246 data->record_event_time = base_event_clock * CYCLE_UNIT / (data->freq_adjusted * data->bytespersample);
247 data->record_event_counter = 0;
248
249 if (data->toccata_active & STATUS_FIFO_PLAY) {
250 audio_enable_sndboard(true);
251 }
252 if (data->toccata_active & STATUS_FIFO_RECORD) {
253 capture_buffer = xcalloc(uae_u8, capture_buffer_size);
254 sndboard_init_capture(data->freq_adjusted);
255 }
256 }
257
codec_stop(void)258 static void codec_stop(void)
259 {
260 struct toccata_data *data = &toccata;
261 write_log(_T("TOCCATA stop\n"));
262 data->toccata_active = 0;
263 sndboard_free_capture();
264 audio_enable_sndboard(false);
265 xfree(capture_buffer);
266 capture_buffer = NULL;
267 }
268
sndboard_rethink(void)269 void sndboard_rethink(void)
270 {
271 struct toccata_data *data = &toccata;
272 uae_int_requested &= ~0x200;
273 if (data->toccata_irq)
274 uae_int_requested |= 0x200;
275 }
276
sndboard_process_capture(void)277 static void sndboard_process_capture(void)
278 {
279 struct toccata_data *data = &toccata;
280 int frames;
281 uae_u8 *buffer = sndboard_get_buffer(&frames);
282 if (buffer && frames) {
283 uae_u8 *p = buffer;
284 int bytes = frames * 4;
285 if (bytes >= capture_buffer_size - capture_write_index) {
286 memcpy(capture_buffer + capture_write_index, p, capture_buffer_size - capture_write_index);
287 p += capture_buffer_size - capture_write_index;
288 bytes -= capture_buffer_size - capture_write_index;
289 capture_write_index = 0;
290 }
291 if (bytes > 0 && bytes < capture_buffer_size - capture_write_index) {
292 memcpy(capture_buffer + capture_write_index, p, bytes);
293 capture_write_index += bytes;
294 }
295 }
296 sndboard_release_buffer(buffer, frames);
297 }
298
sndboard_hsync(void)299 void sndboard_hsync(void)
300 {
301 struct toccata_data *data = &toccata;
302 static int capcnt;
303
304 if (data->autocalibration > 0)
305 data->autocalibration--;
306
307 if (data->toccata_active & STATUS_FIFO_RECORD) {
308
309 capcnt--;
310 if (capcnt <= 0) {
311 sndboard_process_capture();
312 capcnt = data->record_event_time * 312 / (maxhpos * CYCLE_UNIT);
313 }
314
315 data->record_event_counter += maxhpos * CYCLE_UNIT;
316 int bytes = data->record_event_counter / data->record_event_time;
317 bytes &= ~3;
318 if (bytes < 64 || capture_read_index == capture_write_index)
319 return;
320
321 int oldfifo = data->data_in_record_fifo;
322 int oldbytes = bytes;
323 int size = FIFO_SIZE - data->data_in_record_fifo;
324 while (size > 0 && capture_read_index != capture_write_index && bytes > 0) {
325 uae_u8 *fifop = &data->fifo[data->fifo_record_write_index];
326 uae_u8 *bufp = &capture_buffer[capture_read_index];
327
328 if (data->samplebits == 8) {
329 fifop[0] = bufp[1];
330 data->fifo_record_write_index++;
331 data->data_in_record_fifo++;
332 size--;
333 bytes--;
334 if (data->channels == 2) {
335 fifop[1] = bufp[3];
336 data->fifo_record_write_index++;
337 data->data_in_record_fifo++;
338 size--;
339 bytes--;
340 }
341 } else if (data->samplebits == 16) {
342 fifop[0] = bufp[1];
343 fifop[1] = bufp[0];
344 data->fifo_record_write_index += 2;
345 data->data_in_record_fifo += 2;
346 size -= 2;
347 bytes -= 2;
348 if (data->channels == 2) {
349 fifop[2] = bufp[3];
350 fifop[3] = bufp[2];
351 data->fifo_record_write_index += 2;
352 data->data_in_record_fifo += 2;
353 size -= 2;
354 bytes -= 2;
355 }
356 }
357
358 data->fifo_record_write_index %= FIFO_SIZE;
359 capture_read_index += 4;
360 if (capture_read_index >= capture_buffer_size)
361 capture_read_index = 0;
362 }
363
364 write_log(_T("%d %d %d %d\n"), capture_read_index, capture_write_index, size, bytes);
365
366 if (data->data_in_record_fifo > FIFO_SIZE_HALF && oldfifo <= FIFO_SIZE_HALF) {
367 data->fifo_half |= STATUS_FIFO_RECORD;
368 audio_state_sndboard(-1);
369 }
370 data->record_event_counter -= oldbytes * data->record_event_time;
371 }
372 }
373
sndboard_vsync_toccata(void)374 static void sndboard_vsync_toccata(void)
375 {
376 struct toccata_data *data = &toccata;
377 if (data->toccata_active) {
378 calculate_volume_toccata();
379 audio_activate();
380 }
381 }
382
toccata_put(uaecptr addr,uae_u8 v)383 static void toccata_put(uaecptr addr, uae_u8 v)
384 {
385 struct toccata_data *data = &toccata;
386 int idx = data->ad1848_index & 15;
387
388 #if DEBUG_TOCCATA > 2
389 if (addr & 0x4000)
390 write_log(_T("TOCCATA PUT %08x %02x %d PC=%08X\n"), addr, v, idx, M68K_GETPC);
391 #endif
392
393 if ((addr & 0x6801) == 0x6001) {
394 // AD1848 register 0
395 data->ad1848_index = v;
396 } else if ((addr & 0x6801) == 0x6801) {
397 // AD1848 register 1
398 uae_u8 old = data->ad1848_regs[idx];
399 data->ad1848_regs[idx] = v;
400 #if DEBUG_TOCCATA > 0
401 write_log(_T("TOCCATA PUT reg %d = %02x PC=%08x\n"), idx, v, M68K_GETPC);
402 #endif
403 switch(idx)
404 {
405 case 9:
406 if (v & 8) // ACI enabled
407 data->autocalibration = 50;
408 if (!(old & 3) && (v & 3))
409 codec_start();
410 else if ((old & 3) && !(v & 3))
411 codec_stop();
412 break;
413
414 case 2:
415 case 3:
416 case 4:
417 case 5:
418 case 6:
419 case 7:
420 case 8:
421 calculate_volume_toccata();
422 break;
423
424 }
425 } else if ((addr & 0x6800) == 0x2000) {
426 // FIFO input
427 if (data->toccata_status & STATUS_FIFO_PLAY) {
428 // 7202LA datasheet says fifo can't overflow
429 if (((data->fifo_write_index + 1) % FIFO_SIZE) != data->fifo_read_index) {
430 data->fifo[data->fifo_write_index] = v;
431 data->fifo_write_index++;
432 data->fifo_write_index %= FIFO_SIZE;
433 data->data_in_fifo++;
434 }
435 }
436 data->toccata_irq &= ~STATUS_READ_PLAY_HALF;
437 data->fifo_half &= ~STATUS_FIFO_PLAY;
438 } else if ((addr & 0x6800) == 0x0000) {
439 // Board status
440 if (v & STATUS_RESET) {
441 codec_stop();
442 data->toccata_status = 0;
443 data->toccata_irq = 0;
444 v = 0;
445 }
446 if (v == STATUS_ACTIVE) {
447 data->fifo_write_index = 0;
448 data->fifo_read_index = 0;
449 data->data_in_fifo = 0;
450 data->toccata_status = 0;
451 data->toccata_irq = 0;
452 data->fifo_half = 0;
453 }
454 data->toccata_status = v;
455 #if DEBUG_TOCCATA > 0
456 write_log(_T("TOCCATA PUT STATUS %08x %02x %d PC=%08X\n"), addr, v, idx, M68K_GETPC);
457 #endif
458 } else {
459 write_log(_T("TOCCATA PUT UNKNOWN %08x\n"), addr);
460 }
461 }
462
toccata_get(uaecptr addr)463 static uae_u8 toccata_get(uaecptr addr)
464 {
465 struct toccata_data *data = &toccata;
466 int idx = data->ad1848_index & 15;
467 uae_u8 v = 0;
468
469 if ((addr & 0x6801) == 0x6001) {
470 // AD1848 register 0
471 v = data->ad1848_index;
472 } else if ((addr & 0x6801) == 0x6801) {
473 // AD1848 register 1
474 v = data->ad1848_regs[idx];
475 #if DEBUG_TOCCATA > 0
476 write_log(_T("TOCCATA GET reg %d = %02x PC=%08x\n"), idx, v, M68K_GETPC);
477 #endif
478 switch (idx)
479 {
480 case 11:
481 if (data->autocalibration > 10 && data->autocalibration < 30)
482 data->ad1848_regs[11] |= 0x20;
483 else
484 data->ad1848_regs[11] &= ~0x20;
485 break;
486 case 12:
487 // revision
488 v = 0x0a;
489 break;
490 }
491 } else if ((addr & 0x6800) == 0x2000) {
492 // FIFO output
493 v = data->fifo[data->fifo_record_read_index];
494 if (data->toccata_status & STATUS_FIFO_RECORD) {
495 if (data->data_in_record_fifo > 0) {
496 data->fifo_record_read_index++;
497 data->fifo_record_read_index %= FIFO_SIZE;
498 data->data_in_record_fifo--;
499 }
500 }
501 data->toccata_irq &= ~STATUS_READ_RECORD_HALF;
502 data->fifo_half &= ~STATUS_FIFO_RECORD;
503 } else if ((addr & 0x6800) == 0x0000) {
504 // Board status
505 v = STATUS_READ_INTREQ; // active low
506 if (data->toccata_irq) {
507 v &= ~STATUS_READ_INTREQ;
508 v |= data->toccata_irq;
509 data->toccata_irq = 0;
510 }
511 #if DEBUG_TOCCATA > 0
512 write_log(_T("TOCCATA GET STATUS %08x %02x %d PC=%08X\n"), addr, v, idx, M68K_GETPC);
513 #endif
514 } else {
515 write_log(_T("TOCCATA GET UNKNOWN %08x\n"), addr);
516 }
517
518 #if DEBUG_TOCCATA > 2
519 write_log(_T("TOCCATA GET %08x %02x %d PC=%08X\n"), addr, v, idx, M68K_GETPC);
520 #endif
521 return v;
522 }
523
toccata_bput(uaecptr addr,uae_u32 b)524 static void REGPARAM2 toccata_bput(uaecptr addr, uae_u32 b)
525 {
526 struct toccata_data *data = &toccata;
527 b &= 0xff;
528 addr &= BOARD_MASK;
529 if (!data->configured) {
530 switch (addr)
531 {
532 case 0x48:
533 map_banks_z2(&toccata_bank, expamem_z2_pointer >> 16, BOARD_SIZE >> 16);
534 data->configured = 1;
535 expamem_next(&toccata_bank, NULL);
536 break;
537 case 0x4c:
538 data->configured = -1;
539 expamem_shutup(&toccata_bank);
540 break;
541 }
542 return;
543 }
544 if (data->configured > 0)
545 toccata_put(addr, b);
546 }
547
toccata_wput(uaecptr addr,uae_u32 b)548 static void REGPARAM2 toccata_wput(uaecptr addr, uae_u32 b)
549 {
550 toccata_bput(addr + 0, b >> 8);
551 toccata_bput(addr + 1, b >> 0);
552 }
553
toccata_lput(uaecptr addr,uae_u32 b)554 static void REGPARAM2 toccata_lput(uaecptr addr, uae_u32 b)
555 {
556 toccata_bput(addr + 0, b >> 24);
557 toccata_bput(addr + 1, b >> 16);
558 toccata_bput(addr + 2, b >> 8);
559 toccata_bput(addr + 3, b >> 0);
560 }
561
toccata_bget(uaecptr addr)562 static uae_u32 REGPARAM2 toccata_bget(uaecptr addr)
563 {
564 struct toccata_data *data = &toccata;
565 uae_u8 v = 0;
566 addr &= BOARD_MASK;
567 if (!data->configured) {
568 if (addr >= sizeof data->acmemory)
569 return 0;
570 return data->acmemory[addr];
571 }
572 if (data->configured > 0)
573 v = toccata_get(addr);
574 return v;
575 }
toccata_wget(uaecptr addr)576 static uae_u32 REGPARAM2 toccata_wget(uaecptr addr)
577 {
578 uae_u16 v;
579 v = toccata_get(addr) << 8;
580 v |= toccata_get(addr + 1) << 0;
581 return v;
582 }
toccata_lget(uaecptr addr)583 static uae_u32 REGPARAM2 toccata_lget(uaecptr addr)
584 {
585 uae_u32 v;
586 v = toccata_get(addr) << 24;
587 v |= toccata_get(addr + 1) << 16;
588 v |= toccata_get(addr + 2) << 8;
589 v |= toccata_get(addr + 3) << 0;
590 return v;
591 }
592
593 addrbank toccata_bank = {
594 toccata_lget, toccata_wget, toccata_bget,
595 toccata_lput, toccata_wput, toccata_bput,
596 default_xlate, default_check, NULL, NULL, _T("Toccata"),
597 dummy_lgeti, dummy_wgeti,
598 ABFLAG_IO, S_READ, S_WRITE
599 };
600
ew(uae_u8 * acmemory,int addr,uae_u32 value)601 static void ew (uae_u8 *acmemory, int addr, uae_u32 value)
602 {
603 addr &= 0xffff;
604 if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
605 acmemory[addr] = (value & 0xf0);
606 acmemory[addr + 2] = (value & 0x0f) << 4;
607 } else {
608 acmemory[addr] = ~(value & 0xf0);
609 acmemory[addr + 2] = ~((value & 0x0f) << 4);
610 }
611 }
612
sndboard_init(int devnum)613 addrbank *sndboard_init(int devnum)
614 {
615 struct toccata_data *data = &toccata;
616 memset(data->ad1848_regs, 0, sizeof data->ad1848_regs);
617 data->ad1848_regs[2] = 0x80;
618 data->ad1848_regs[3] = 0x80;
619 data->ad1848_regs[4] = 0x80;
620 data->ad1848_regs[5] = 0x80;
621 data->ad1848_regs[6] = 0x80;
622 data->ad1848_regs[7] = 0x80;
623 data->ad1848_regs[9] = 0x10;
624 data->ad1848_status = 0xcc;
625 data->ad1848_index = 0x40;
626 calculate_volume_toccata();
627
628 data->configured = 0;
629 memset(data->acmemory, 0xff, sizeof data->acmemory);
630 for (int i = 0; i < 16; i++) {
631 uae_u8 b = toccata_autoconfig[i];
632 ew(data->acmemory, i * 4, b);
633 }
634 return &toccata_bank;
635 }
636
sndboard_free(void)637 void sndboard_free(void)
638 {
639 struct toccata_data *data = &toccata;
640 data->toccata_irq = 0;
641 uae_int_requested &= ~0x200;
642 }
643
sndboard_reset(void)644 void sndboard_reset(void)
645 {
646 struct toccata_data *data = &toccata;
647 data->ch_sample[0] = 0;
648 data->ch_sample[1] = 0;
649 audio_enable_sndboard(false);
650 }
651
652 struct fm801_data
653 {
654 struct pci_board_state *pcibs;
655 uaecptr play_dma[2], play_dma2[2];
656 uae_u16 play_len, play_len2;
657 uae_u16 play_control;
658 uae_u16 interrupt_control;
659 uae_u16 interrupt_status;
660 int dmach;
661 int freq;
662 int bits;
663 int ch;
664 int bytesperframe;
665 bool play_on;
666 int left_volume, right_volume;
667 int ch_sample[2];
668 int event_time;
669 };
670 static struct fm801_data fm801;
671 static bool fm801_active;
672 static const int fm801_freq[16] = { 5500, 8000, 9600, 11025, 16000, 19200, 22050, 32000, 38400, 44100, 48000 };
673
calculate_volume_fm801(void)674 static void calculate_volume_fm801(void)
675 {
676 struct fm801_data *data = &fm801;
677 data->left_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
678 data->right_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
679 }
680
sndboard_vsync_fm801(void)681 static void sndboard_vsync_fm801(void)
682 {
683 audio_activate();
684 calculate_volume_fm801();
685 }
686
fm801_stop(struct fm801_data * data)687 static void fm801_stop(struct fm801_data *data)
688 {
689 write_log(_T("FM801 STOP\n"));
690 data->play_on = false;
691 audio_enable_sndboard(false);
692 }
693
fm801_swap_buffers(struct fm801_data * data)694 static void fm801_swap_buffers(struct fm801_data *data)
695 {
696 data->dmach = data->dmach ? 0 : 1;
697 data->play_dma2[data->dmach] = data->play_dma[data->dmach];
698 data->play_len2 = data->play_len;
699 // stop at the end of buffer
700 if (!(data->play_control & 0x20) && !(data->play_control & 0x80))
701 fm801_stop(data);
702 }
703
fm801_interrupt(struct fm801_data * data)704 static void fm801_interrupt(struct fm801_data *data)
705 {
706 if ((data->interrupt_status & 0x100) && !(data->interrupt_control & 1)) {
707 data->pcibs->board->irq(data->pcibs, true);
708 } else {
709 data->pcibs->board->irq(data->pcibs, false);
710 }
711 }
712
audio_state_sndboard_fm801(int ch)713 static void audio_state_sndboard_fm801(int ch)
714 {
715 struct fm801_data *data = &fm801;
716
717 if (data->play_on && ch == 0) {
718 uae_u8 sample[2 * 6] = { 0 };
719 uae_s16 l, r;
720 pci_read_dma(data->pcibs, data->play_dma2[data->dmach], sample, data->bytesperframe);
721 if (data->bits == 8) {
722 if (data->ch == 1) {
723 sample[1] = sample[0];
724 sample[2] = sample[0];
725 sample[3] = sample[0];
726 } else {
727 sample[2] = sample[1];
728 sample[3] = sample[1];
729 sample[1] = sample[0];
730 }
731 } else {
732 if (data->ch == 1) {
733 sample[2] = sample[0];
734 sample[3] = sample[1];
735 }
736 }
737 l = (sample[1] << 8) | sample[0];
738 r = (sample[3] << 8) | sample[2];
739 data->ch_sample[0] = l;
740 data->ch_sample[1] = r;
741 data->ch_sample[0] = data->ch_sample[0] * data->left_volume / 32768;
742 data->ch_sample[1] = data->ch_sample[1] * data->right_volume / 32768;
743
744 data->play_len2 -= data->bytesperframe;
745 data->play_dma2[data->dmach] += data->bytesperframe;
746 if (data->play_len2 == 0xffff) {
747 fm801_swap_buffers(data);
748 data->interrupt_status |= 0x100;
749 fm801_interrupt(data);
750 }
751 }
752 audio_state_sndboard_state(ch, data->ch_sample[ch], data->event_time);
753 }
754
fm801_hsync_handler(struct pci_board_state * pcibs)755 static void fm801_hsync_handler(struct pci_board_state *pcibs)
756 {
757 }
758
fm801_play(struct fm801_data * data)759 static void fm801_play(struct fm801_data *data)
760 {
761 uae_u16 control = data->play_control;
762 int f = (control >> 8) & 15;
763 data->freq = fm801_freq[f];
764 if (!data->freq)
765 data->freq = 44100;
766 data->event_time = base_event_clock * CYCLE_UNIT / data->freq;
767 data->bits = (control & 0x4000) ? 16 : 8;
768 f = (control >> 12) & 3;
769 switch (f)
770 {
771 case 0:
772 data->ch = (control & 0x8000) ? 2 : 1;
773 break;
774 case 1:
775 data->ch = 4;
776 break;
777 case 2:
778 data->ch = 6;
779 break;
780 case 3:
781 data->ch = 6;
782 break;
783 }
784 data->bytesperframe = data->bits * data->ch / 8;
785 data->play_on = true;
786
787 data->dmach = 1;
788 fm801_swap_buffers(data);
789
790 calculate_volume_fm801();
791
792 write_log(_T("FM801 PLAY: freq=%d ch=%d bits=%d\n"), data->freq, data->ch, data->bits);
793
794 audio_enable_sndboard(true);
795 }
796
fm801_pause(struct fm801_data * data,bool pause)797 static void fm801_pause(struct fm801_data *data, bool pause)
798 {
799 write_log(_T("FM801 PAUSED %d\n"), pause);
800 }
fm801_control(struct fm801_data * data,uae_u16 control)801 static void fm801_control(struct fm801_data *data, uae_u16 control)
802 {
803 uae_u16 old_control = data->play_control;
804 data->play_control = control;
805 data->play_control &= ~(8 | 16);
806 if ((data->play_control & 0x20) && !(old_control & 0x20)) {
807 fm801_play(data);
808 } else if (!(data->play_control & 0x20) && (old_control & 0x20)) {
809 if (data->play_control & 0x80)
810 fm801_stop(data);
811 } else if (data->play_control & 0x20) {
812 if ((data->play_control & 0x40) && !(old_control & 0x40)) {
813 fm801_pause(data, true);
814 } else if (!(data->play_control & 0x40) && (old_control & 0x40)) {
815 fm801_pause(data, true);
816 }
817 }
818
819 }
820
fm801_bput(struct pci_board_state * pcibs,uaecptr addr,uae_u32 b)821 static void REGPARAM2 fm801_bput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
822 {
823 struct fm801_data *data = &fm801;
824 }
fm801_wput(struct pci_board_state * pcibs,uaecptr addr,uae_u32 b)825 static void REGPARAM2 fm801_wput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
826 {
827 struct fm801_data *data = &fm801;
828 switch (addr)
829 {
830 case 0x08:
831 fm801_control(data, b);
832 break;
833 case 0x0a:
834 data->play_len = b;
835 break;
836 case 0x56:
837 data->interrupt_control = b;
838 fm801_interrupt(data);
839 break;
840 case 0x5a:
841 data->interrupt_status &= ~b;
842 fm801_interrupt(data);
843 break;
844 }
845 }
fm801_lput(struct pci_board_state * pcibs,uaecptr addr,uae_u32 b)846 static void REGPARAM2 fm801_lput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
847 {
848 struct fm801_data *data = &fm801;
849 switch (addr)
850 {
851 case 0x0c:
852 data->play_dma[0] = b;
853 break;
854 case 0x10:
855 data->play_dma[1] = b;
856 break;
857 }
858 }
fm801_bget(struct pci_board_state * pcibs,uaecptr addr)859 static uae_u32 REGPARAM2 fm801_bget(struct pci_board_state *pcibs, uaecptr addr)
860 {
861 struct fm801_data *data = &fm801;
862 uae_u32 v = 0;
863 return v;
864 }
fm801_wget(struct pci_board_state * pcibs,uaecptr addr)865 static uae_u32 REGPARAM2 fm801_wget(struct pci_board_state *pcibs, uaecptr addr)
866 {
867 struct fm801_data *data = &fm801;
868 uae_u32 v = 0;
869 switch (addr) {
870 case 0x08:
871 v = data->play_control;
872 break;
873 case 0x0a:
874 v = data->play_len2;
875 break;
876 case 0x56:
877 v = data->interrupt_control;
878 break;
879 case 0x5a:
880 v = data->interrupt_status;
881 break;
882
883 }
884 return v;
885 }
fm801_lget(struct pci_board_state * pcibs,uaecptr addr)886 static uae_u32 REGPARAM2 fm801_lget(struct pci_board_state *pcibs, uaecptr addr)
887 {
888 struct fm801_data *data = &fm801;
889 uae_u32 v = 0;
890 switch(addr)
891 {
892 case 0x0c:
893 v = data->play_dma2[data->dmach];
894 break;
895 case 0x10:
896 v = data->play_dma2[data->dmach];
897 break;
898 }
899 return v;
900 }
901
fm801_reset(struct pci_board_state * pcibs)902 static void fm801_reset(struct pci_board_state *pcibs)
903 {
904 struct fm801_data *data = &fm801;
905 data->play_control = 0xca00;
906 data->interrupt_control = 0x00df;
907 }
908
fm801_free(struct pci_board_state * pcibs)909 static void fm801_free(struct pci_board_state *pcibs)
910 {
911 struct fm801_data *data = &fm801;
912 fm801_active = false;
913 fm801_stop(data);
914 }
915
fm801_init(struct pci_board_state * pcibs)916 static bool fm801_init(struct pci_board_state *pcibs)
917 {
918 struct fm801_data *data = &fm801;
919 memset(data, 0, sizeof(struct fm801_data));
920 data->pcibs = pcibs;
921 fm801_active = true;
922 return false;
923 }
924
925 static const struct pci_config fm801_pci_config =
926 {
927 0x1319, 0x0801, 0, 0, 0xb2, 0x040100, 0x80, 0x1319, 0x1319, 1, 0x04, 0x28, { 128 | 1, 0, 0, 0, 0, 0, 0 }
928 };
929 static const struct pci_config fm801_pci_config_func1 =
930 {
931 0x1319, 0x0802, 0, 0, 0xb2, 0x098000, 0x80, 0x1319, 0x1319, 0, 0x04, 0x28, { 16 | 1, 0, 0, 0, 0, 0, 0 }
932 };
933
934 const struct pci_board fm801_pci_board =
935 {
936 _T("FM801"),
937 &fm801_pci_config, fm801_init, fm801_free, fm801_reset, fm801_hsync_handler, pci_irq_callback,
938 {
939 { fm801_lget, fm801_wget, fm801_bget, fm801_lput, fm801_wput, fm801_bput },
940 { NULL },
941 { NULL },
942 { NULL },
943 { NULL },
944 { NULL },
945 { NULL },
946 }
947 };
948
949 const struct pci_board fm801_pci_board_func1 =
950 {
951 _T("FM801-2"),
952 &fm801_pci_config_func1, NULL, NULL, NULL, NULL, NULL,
953 {
954 { fm801_lget, fm801_wget, fm801_bget, fm801_lput, fm801_wput, fm801_bput },
955 { NULL },
956 { NULL },
957 { NULL },
958 { NULL },
959 { NULL },
960 { NULL },
961 }
962 };
963
solo1_reset(struct pci_board_state * pcibs)964 static void solo1_reset(struct pci_board_state *pcibs)
965 {
966 }
967
solo1_free(struct pci_board_state * pcibs)968 static void solo1_free(struct pci_board_state *pcibs)
969 {
970 }
971
solo1_init(struct pci_board_state * pcibs)972 static bool solo1_init(struct pci_board_state *pcibs)
973 {
974 return true;
975 }
976
solo1_sb_put(struct pci_board_state * pcibs,uaecptr addr,uae_u32 b)977 static void solo1_sb_put(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
978 {
979 }
solo1_sb_get(struct pci_board_state * pcibs,uaecptr addr)980 static uae_u32 solo1_sb_get(struct pci_board_state *pcibs, uaecptr addr)
981 {
982 uae_u32 v = 0;
983 return v;
984 }
985
solo1_put(struct pci_board_state * pcibs,int bar,uaecptr addr,uae_u32 b)986 static void solo1_put(struct pci_board_state *pcibs, int bar, uaecptr addr, uae_u32 b)
987 {
988 if (bar == 1)
989 solo1_sb_put(pcibs, addr, b);
990 }
solo1_get(struct pci_board_state * pcibs,int bar,uaecptr addr)991 static uae_u32 solo1_get(struct pci_board_state *pcibs, int bar, uaecptr addr)
992 {
993 uae_u32 v = 0;
994 if (bar == 1)
995 v = solo1_sb_get(pcibs, addr);
996 return v;
997 }
998
solo1_bput(struct pci_board_state * pcibs,uaecptr addr,uae_u32 b)999 static void REGPARAM2 solo1_bput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
1000 {
1001 write_log(_T("SOLO1 BPUT %08x=%08x %d\n"), addr, b, pcibs->selected_bar);
1002 solo1_put(pcibs, pcibs->selected_bar, addr + 0, b >> 24);
1003 solo1_put(pcibs, pcibs->selected_bar, addr + 1, b >> 16);
1004 solo1_put(pcibs, pcibs->selected_bar, addr + 2, b >> 8);
1005 solo1_put(pcibs, pcibs->selected_bar, addr + 3, b >> 0);
1006 }
solo1_wput(struct pci_board_state * pcibs,uaecptr addr,uae_u32 b)1007 static void REGPARAM2 solo1_wput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
1008 {
1009 write_log(_T("SOLO1 WPUT %08x=%08x %d\n"), addr, b, pcibs->selected_bar);
1010 solo1_put(pcibs, pcibs->selected_bar, addr + 0, b >> 8);
1011 solo1_put(pcibs, pcibs->selected_bar, addr + 1, b >> 0);
1012 }
solo1_lput(struct pci_board_state * pcibs,uaecptr addr,uae_u32 b)1013 static void REGPARAM2 solo1_lput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
1014 {
1015 write_log(_T("SOLO1 LPUT %08x=%08x %d\n"), addr, b, pcibs->selected_bar);
1016 solo1_put(pcibs, pcibs->selected_bar, addr, b);
1017 }
solo1_bget(struct pci_board_state * pcibs,uaecptr addr)1018 static uae_u32 REGPARAM2 solo1_bget(struct pci_board_state *pcibs, uaecptr addr)
1019 {
1020 uae_u32 v = 0;
1021 v = solo1_get(pcibs, pcibs->selected_bar, addr);
1022 write_log(_T("SOLO1 BGET %08x %d\n"), addr, pcibs->selected_bar);
1023 return v;
1024 }
solo1_wget(struct pci_board_state * pcibs,uaecptr addr)1025 static uae_u32 REGPARAM2 solo1_wget(struct pci_board_state *pcibs, uaecptr addr)
1026 {
1027 uae_u32 v = 0;
1028 write_log(_T("SOLO1 WGET %08x %d\n"), addr, pcibs->selected_bar);
1029 return v;
1030 }
solo1_lget(struct pci_board_state * pcibs,uaecptr addr)1031 static uae_u32 REGPARAM2 solo1_lget(struct pci_board_state *pcibs, uaecptr addr)
1032 {
1033 uae_u32 v = 0;
1034 write_log(_T("SOLO1 LGET %08x %d\n"), addr, pcibs->selected_bar);
1035 return v;
1036 }
1037
1038 static const struct pci_config solo1_pci_config =
1039 {
1040 0x125d, 0x1969, 0, 0, 0, 0x040100, 0, 0x125d, 0x1818, 1, 2, 0x18, { 16 | 1, 16 | 1, 16 | 1, 4 | 1, 4 | 1, 0, 0 }
1041 };
1042 const struct pci_board solo1_pci_board =
1043 {
1044 _T("SOLO1"),
1045 &solo1_pci_config, solo1_init, solo1_free, solo1_reset, NULL, pci_irq_callback,
1046 {
1047 { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
1048 { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
1049 { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
1050 { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
1051 { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
1052 { NULL },
1053 { NULL },
1054 }
1055 };
1056
1057 static SWVoiceOut *qemu_voice_out;
1058
calculate_volume_qemu(void)1059 static void calculate_volume_qemu(void)
1060 {
1061 SWVoiceOut *out = qemu_voice_out;
1062 if (!out)
1063 return;
1064 out->left_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
1065 out->right_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
1066 }
1067
AUD_close_in(QEMUSoundCard * card,SWVoiceIn * sw)1068 void AUD_close_in(QEMUSoundCard *card, SWVoiceIn *sw)
1069 {
1070 }
AUD_read(SWVoiceIn * sw,void * pcm_buf,int size)1071 int AUD_read(SWVoiceIn *sw, void *pcm_buf, int size)
1072 {
1073 return size;
1074 }
AUD_write(SWVoiceOut * sw,void * pcm_buf,int size)1075 int AUD_write(SWVoiceOut *sw, void *pcm_buf, int size)
1076 {
1077 memcpy(sw->samplebuf, pcm_buf, size);
1078 sw->samplebuf_total = size;
1079 return sw->samplebuf_total;
1080 }
AUD_set_active_out(SWVoiceOut * sw,int on)1081 void AUD_set_active_out(SWVoiceOut *sw, int on)
1082 {
1083 sw->active = on != 0;
1084 sw->event_time = base_event_clock * CYCLE_UNIT / sw->freq;
1085 sw->samplebuf_index = 0;
1086 sw->samplebuf_total = 0;
1087 calculate_volume_qemu();
1088 audio_enable_sndboard(sw->active);
1089 }
AUD_set_active_in(SWVoiceIn * sw,int on)1090 void AUD_set_active_in(SWVoiceIn *sw, int on)
1091 {
1092 }
AUD_is_active_in(SWVoiceIn * sw)1093 int AUD_is_active_in(SWVoiceIn *sw)
1094 {
1095 return 0;
1096 }
AUD_close_out(QEMUSoundCard * card,SWVoiceOut * sw)1097 void AUD_close_out(QEMUSoundCard *card, SWVoiceOut *sw)
1098 {
1099 qemu_voice_out = NULL;
1100 audio_enable_sndboard(false);
1101 xfree(sw);
1102 }
AUD_open_in(QEMUSoundCard * card,SWVoiceIn * sw,const char * name,void * callback_opaque,audio_callback_fn callback_fn,struct audsettings * settings)1103 SWVoiceIn *AUD_open_in(
1104 QEMUSoundCard *card,
1105 SWVoiceIn *sw,
1106 const char *name,
1107 void *callback_opaque,
1108 audio_callback_fn callback_fn,
1109 struct audsettings *settings)
1110 {
1111 return NULL;
1112 }
AUD_open_out(QEMUSoundCard * card,SWVoiceOut * sw,const char * name,void * callback_opaque,audio_callback_fn callback_fn,struct audsettings * settings)1113 SWVoiceOut *AUD_open_out(
1114 QEMUSoundCard *card,
1115 SWVoiceOut *sw,
1116 const char *name,
1117 void *callback_opaque,
1118 audio_callback_fn callback_fn,
1119 struct audsettings *settings)
1120 {
1121 SWVoiceOut *out = sw;
1122 if (!sw)
1123 out = xcalloc(SWVoiceOut, 1);
1124 int bits = 8;
1125
1126 if (settings->fmt >= AUD_FMT_U16)
1127 bits = 16;
1128 if (settings->fmt >= AUD_FMT_U32)
1129 bits = 32;
1130
1131 out->callback = callback_fn;
1132 out->opaque = callback_opaque;
1133 out->bits = bits;
1134 out->freq = settings->freq;
1135 out->ch = settings->nchannels;
1136 out->fmt = settings->fmt;
1137 out->bytesperframe = out->ch * bits / 8;
1138
1139 write_log(_T("QEMU AUDIO: freq=%d ch=%d bits=%d (fmt=%d) '%s'\n"), out->freq, out->ch, bits, settings->fmt, name);
1140
1141 qemu_voice_out = out;
1142
1143 return out;
1144 }
1145
audio_state_sndboard_qemu(int ch)1146 static void audio_state_sndboard_qemu(int ch)
1147 {
1148 SWVoiceOut *out = qemu_voice_out;
1149
1150 if (!out)
1151 return;
1152 if (out->active && ch == 0) {
1153 uae_s16 l, r;
1154 if (out->samplebuf_index >= out->samplebuf_total) {
1155 int maxsize = sizeof(out->samplebuf);
1156 int size = 128 * out->bytesperframe;
1157 if (size > maxsize)
1158 size = maxsize;
1159 out->callback(out->opaque, size);
1160 out->samplebuf_index = 0;
1161 }
1162 uae_u8 *p = out->samplebuf + out->samplebuf_index;
1163 if (out->bits == 8) {
1164 if (out->ch == 1) {
1165 p[1] = p[0];
1166 p[2] = p[0];
1167 p[3] = p[0];
1168 } else {
1169 p[2] = p[1];
1170 p[3] = p[1];
1171 p[1] = p[0];
1172 }
1173 } else {
1174 if (out->ch == 1) {
1175 p[2] = p[0];
1176 p[3] = p[1];
1177 }
1178 }
1179 l = (p[1] << 8) | p[0];
1180 r = (p[3] << 8) | p[2];
1181 out->ch_sample[0] = l;
1182 out->ch_sample[1] = r;
1183 out->ch_sample[0] = out->ch_sample[0] * out->left_volume / 32768;
1184 out->ch_sample[1] = out->ch_sample[1] * out->right_volume / 32768;
1185 out->samplebuf_index += out->bytesperframe;
1186 }
1187 audio_state_sndboard_state(ch, out->ch_sample[ch], out->event_time);
1188 }
1189
1190
sndboard_vsync_qemu(void)1191 static void sndboard_vsync_qemu(void)
1192 {
1193 audio_activate();
1194 }
1195
1196
audio_state_sndboard(int ch)1197 void audio_state_sndboard(int ch)
1198 {
1199 if (toccata.toccata_active)
1200 audio_state_sndboard_toccata(ch);
1201 if (fm801_active)
1202 audio_state_sndboard_fm801(ch);
1203 if (qemu_voice_out && qemu_voice_out->active)
1204 audio_state_sndboard_qemu(ch);
1205 }
1206
sndboard_vsync(void)1207 void sndboard_vsync(void)
1208 {
1209 if (toccata.toccata_active)
1210 sndboard_vsync_toccata();
1211 if (fm801_active)
1212 sndboard_vsync_fm801();
1213 if (qemu_voice_out && qemu_voice_out->active)
1214 sndboard_vsync_qemu();
1215 }
1216
sndboard_ext_volume(void)1217 void sndboard_ext_volume(void)
1218 {
1219 if (toccata.toccata_active)
1220 calculate_volume_toccata();
1221 if (fm801_active)
1222 calculate_volume_fm801();
1223 if (qemu_voice_out && qemu_voice_out->active)
1224 calculate_volume_qemu();
1225 }
1226
1227 #ifdef FSUAE
1228
sndboard_get_buffer(int * frames)1229 static uae_u8 *sndboard_get_buffer(int *frames)
1230 {
1231 return NULL;
1232 }
1233
sndboard_release_buffer(uae_u8 * buffer,int frames)1234 static void sndboard_release_buffer(uae_u8 *buffer, int frames)
1235 {
1236 }
1237
sndboard_free_capture(void)1238 static void sndboard_free_capture(void)
1239 {
1240 }
1241
sndboard_init_capture(int freq)1242 static bool sndboard_init_capture(int freq)
1243 {
1244 return false;
1245 }
1246
1247 #else
1248 #ifdef _WIN32
1249
1250 #include <mmdeviceapi.h>
1251 #include <Audioclient.h>
1252
1253 #define REFTIMES_PER_SEC 10000000
1254
1255 static const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
1256 static const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
1257 static const IID IID_IAudioClient = __uuidof(IAudioClient);
1258 static const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
1259
1260 #define EXIT_ON_ERROR(hres) if (FAILED(hres)) { goto Exit; }
1261 #define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->Release(); (punk) = NULL; }
1262
1263 static IMMDeviceEnumerator *pEnumerator = NULL;
1264 static IMMDevice *pDevice = NULL;
1265 static IAudioClient *pAudioClient = NULL;
1266 static IAudioCaptureClient *pCaptureClient = NULL;
1267 static bool capture_started;
1268
sndboard_get_buffer(int * frames)1269 static uae_u8 *sndboard_get_buffer(int *frames)
1270 {
1271 HRESULT hr;
1272 UINT32 numFramesAvailable;
1273 BYTE *pData;
1274 DWORD flags = 0;
1275
1276 *frames = -1;
1277 if (!capture_started)
1278 return NULL;
1279 hr = pCaptureClient->GetBuffer(&pData, &numFramesAvailable, &flags, NULL, NULL);
1280 if (FAILED(hr)) {
1281 write_log(_T("GetBuffer failed %08x\n"), hr);
1282 return NULL;
1283 }
1284 *frames = numFramesAvailable;
1285 return pData;
1286 }
1287
sndboard_release_buffer(uae_u8 * buffer,int frames)1288 static void sndboard_release_buffer(uae_u8 *buffer, int frames)
1289 {
1290 HRESULT hr;
1291 if (!capture_started || frames < 0)
1292 return;
1293 hr = pCaptureClient->ReleaseBuffer(frames);
1294 if (FAILED(hr)) {
1295 write_log(_T("ReleaseBuffer failed %08x\n"), hr);
1296 }
1297 }
1298
sndboard_free_capture(void)1299 static void sndboard_free_capture(void)
1300 {
1301 if (capture_started)
1302 pAudioClient->Stop();
1303 capture_started = false;
1304 SAFE_RELEASE(pEnumerator)
1305 SAFE_RELEASE(pDevice)
1306 SAFE_RELEASE(pAudioClient)
1307 SAFE_RELEASE(pCaptureClient)
1308 }
1309
sndboard_init_capture(int freq)1310 static bool sndboard_init_capture(int freq)
1311 {
1312 HRESULT hr;
1313 WAVEFORMATEX wavfmtsrc;
1314 WAVEFORMATEX *wavfmt2;
1315 WAVEFORMATEX *wavfmt;
1316
1317 wavfmt2 = NULL;
1318
1319 hr = CoCreateInstance(
1320 CLSID_MMDeviceEnumerator, NULL,
1321 CLSCTX_ALL, IID_IMMDeviceEnumerator,
1322 (void**)&pEnumerator);
1323 EXIT_ON_ERROR(hr)
1324
1325 hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
1326 EXIT_ON_ERROR(hr)
1327
1328 hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
1329 EXIT_ON_ERROR(hr)
1330
1331 memset (&wavfmtsrc, 0, sizeof wavfmtsrc);
1332 wavfmtsrc.nChannels = 2;
1333 wavfmtsrc.nSamplesPerSec = freq;
1334 wavfmtsrc.wBitsPerSample = 16;
1335 wavfmtsrc.wFormatTag = WAVE_FORMAT_PCM;
1336 wavfmtsrc.cbSize = 0;
1337 wavfmtsrc.nBlockAlign = wavfmtsrc.wBitsPerSample / 8 * wavfmtsrc.nChannels;
1338 wavfmtsrc.nAvgBytesPerSec = wavfmtsrc.nBlockAlign * wavfmtsrc.nSamplesPerSec;
1339
1340 bool init = false;
1341 AUDCLNT_SHAREMODE exc;
1342 for (int mode = 0; mode < 2; mode++) {
1343 exc = mode == 0 ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED;
1344 int time = mode == 0 ? 0 : REFTIMES_PER_SEC / 50;
1345
1346 wavfmt = &wavfmtsrc;
1347 hr = pAudioClient->IsFormatSupported(exc, &wavfmtsrc, &wavfmt2);
1348 if (SUCCEEDED(hr)) {
1349 hr = pAudioClient->Initialize(exc, 0, time, 0, wavfmt, NULL);
1350 if (SUCCEEDED(hr)) {
1351 init = true;
1352 break;
1353 }
1354 }
1355
1356 if (hr == S_FALSE && wavfmt2) {
1357 wavfmt = wavfmt2;
1358 hr = pAudioClient->Initialize(exc, 0, time, 0, wavfmt, NULL);
1359 if (SUCCEEDED(hr)) {
1360 init = true;
1361 break;
1362 }
1363 }
1364 }
1365
1366 if (!init) {
1367 write_log(_T("sndboard capture init, freq=%d, failed\n"), freq);
1368 goto Exit;
1369 }
1370
1371
1372 hr = pAudioClient->GetService(IID_IAudioCaptureClient, (void**)&pCaptureClient);
1373 EXIT_ON_ERROR(hr)
1374
1375 hr = pAudioClient->Start();
1376 EXIT_ON_ERROR(hr)
1377 capture_started = true;
1378
1379 CoTaskMemFree(wavfmt2);
1380
1381 write_log(_T("sndboard capture started: freq=%d mode=%s\n"), freq, exc == AUDCLNT_SHAREMODE_EXCLUSIVE ? _T("exclusive") : _T("shared"));
1382
1383 return true;
1384 Exit:;
1385 CoTaskMemFree(wavfmt2);
1386 write_log(_T("sndboard capture init failed %08x\n"), hr);
1387 sndboard_free_capture();
1388 return false;
1389 }
1390
1391 #endif
1392 #endif
1393