]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
FM801 emulation.
authorToni Wilen <twilen@winuae.net>
Mon, 6 Jul 2015 17:25:22 +0000 (20:25 +0300)
committerToni Wilen <twilen@winuae.net>
Mon, 6 Jul 2015 17:25:22 +0000 (20:25 +0300)
sndboard.cpp

index 5e21bf11b48732d060658f76495994a044f91cab..91afc8e3d8ba480c957978586892d2005d0f0939 100644 (file)
 #include "custom.h"
 #include "sndboard.h"
 #include "audio.h"
-
+#include "autoconf.h"
+#include "pci_hw.h"
+#include "qemuvga/qemuaudio.h"
 
 static uae_u8 *sndboard_get_buffer(int *frames);
 static void sndboard_release_buffer(uae_u8 *buffer, int frames);
 static void sndboard_free_capture(void);
 static bool sndboard_init_capture(int freq);
 
+static double base_event_clock;
+
 #define DEBUG_TOCCATA 0
 
 #define BOARD_MASK 65535
 #define BOARD_SIZE 65536
 
-static const uae_u8 toccata_autoconfig[16] = { 0xc1, 12, 0, 0, 18260 >> 8, 18260 & 255 };
-static uae_u8 acmemory[128];
-static int configured;
-static uae_u8 ad1848_index;
-static uae_u8 ad1848_regs[16];
-static uae_u8 ad1848_status;
-static int autocalibration;
-extern addrbank toccata_bank;
-static uae_u8 toccata_status;
-static int toccata_irq;
-
 #define FIFO_SIZE 1024
 #define FIFO_SIZE_HALF (FIFO_SIZE / 2)
 
-static int fifo_read_index;
-static int fifo_write_index;
-static int data_in_fifo;
-static uae_u8 fifo[FIFO_SIZE];
+static const uae_u8 toccata_autoconfig[16] = { 0xc1, 12, 0, 0, 18260 >> 8, 18260 & 255 };
 
-static int fifo_record_read_index;
-static int fifo_record_write_index;
-static int data_in_record_fifo;
-static uae_u8 record_fifo[FIFO_SIZE];
+struct toccata_data {
+       uae_u8 acmemory[128];
+       int configured;
+       uae_u8 ad1848_index;
+       uae_u8 ad1848_regs[16];
+       uae_u8 ad1848_status;
+       int autocalibration;
+       uae_u8 toccata_status;
+       int toccata_irq;
+       int fifo_read_index;
+       int fifo_write_index;
+       int data_in_fifo;
+       uae_u8 fifo[FIFO_SIZE];
+
+       int fifo_record_read_index;
+       int fifo_record_write_index;
+       int data_in_record_fifo;
+       uae_u8 record_fifo[FIFO_SIZE];
+
+       int ch_sample[2];
+
+       int fifo_half;
+       int toccata_active;
+       int left_volume, right_volume;
+
+       int freq, freq_adjusted, channels, samplebits;
+       int event_time, record_event_time;
+       int record_event_counter;
+       int bytespersample;
+};
 
-static int fifo_half;
-static int toccata_active;
-static int left_volume, right_volume;
+static struct toccata_data toccata;
 
+extern addrbank toccata_bank;
 
 #define STATUS_ACTIVE 1
 #define STATUS_RESET 2
@@ -71,78 +86,73 @@ static int left_volume, right_volume;
 #define STATUS_READ_PLAY_HALF 8
 #define STATUS_READ_RECORD_HALF 4
 
-static int freq, freq_adjusted, channels, samplebits;
-static int event_time, record_event_time;
-static int record_event_counter;
-static double base_event_clock;
-static int bytespersample;
 
 void update_sndboard_sound (double clk)
 {
        base_event_clock = clk;
 }
 
-static int ch_sample[2];
-
 static void process_fifo(void)
 {
-       int prev_data_in_fifo = data_in_fifo;
-       if (data_in_fifo >= bytespersample) {
+       struct toccata_data *data = &toccata;
+       int prev_data_in_fifo = data->data_in_fifo;
+       if (data->data_in_fifo >= data->bytespersample) {
                uae_s16 v;
-               if (samplebits == 8) {
-                       v = fifo[fifo_read_index] << 8;
-                       v |= fifo[fifo_read_index];
-                       ch_sample[0] = v;
-                       if (channels == 2) {
-                               v = fifo[fifo_read_index + 1] << 8;
-                               v |= fifo[fifo_read_index + 1];
+               if (data->samplebits == 8) {
+                       v = data->fifo[data->fifo_read_index] << 8;
+                       v |= data->fifo[data->fifo_read_index];
+                       data->ch_sample[0] = v;
+                       if (data->channels == 2) {
+                               v = data->fifo[data->fifo_read_index + 1] << 8;
+                               v |= data->fifo[data->fifo_read_index + 1];
                        }
-                       ch_sample[1] = v;
-               } else if (samplebits == 16) {
-                       v = fifo[fifo_read_index + 1] << 8;
-                       v |= fifo[fifo_read_index + 0];
-                       ch_sample[0] = v;
-                       if (channels == 2) {
-                               v = fifo[fifo_read_index + 3] << 8;
-                               v |= fifo[fifo_read_index + 2];
+                       data->ch_sample[1] = v;
+               } else if (data->samplebits == 16) {
+                       v = data->fifo[data->fifo_read_index + 1] << 8;
+                       v |= data->fifo[data->fifo_read_index + 0];
+                       data->ch_sample[0] = v;
+                       if (data->channels == 2) {
+                               v = data->fifo[data->fifo_read_index + 3] << 8;
+                               v |= data->fifo[data->fifo_read_index + 2];
                        }
-                       ch_sample[1] = v;
+                       data->ch_sample[1] = v;
                }
-               data_in_fifo -= bytespersample;
-               fifo_read_index += bytespersample;
-               fifo_read_index = fifo_read_index % FIFO_SIZE;
+               data->data_in_fifo -= data->bytespersample;
+               data->fifo_read_index += data->bytespersample;
+               data->fifo_read_index = data->fifo_read_index % FIFO_SIZE;
        }
 
-       ch_sample[0] = ch_sample[0] * left_volume / 32768;
-       ch_sample[1] = ch_sample[1] * right_volume / 32768;
+       data->ch_sample[0] = data->ch_sample[0] * data->left_volume / 32768;
+       data->ch_sample[1] = data->ch_sample[1] * data->right_volume / 32768;
 
-       if (data_in_fifo < FIFO_SIZE_HALF && prev_data_in_fifo >= FIFO_SIZE_HALF)
-               fifo_half |= STATUS_FIFO_PLAY;
+       if (data->data_in_fifo < FIFO_SIZE_HALF && prev_data_in_fifo >= FIFO_SIZE_HALF)
+               data->fifo_half |= STATUS_FIFO_PLAY;
 }
 
-void audio_state_sndboard(int ch)
+static void audio_state_sndboard_toccata(int ch)
 {
-       if ((toccata_active & STATUS_FIFO_PLAY) && ch == 0) {
+       struct toccata_data *data = &toccata;
+       if ((data->toccata_active & STATUS_FIFO_PLAY) && ch == 0) {
                // get all bytes at once to prevent fifo going out of sync
                // if fifo has for example 3 bytes remaining but we need 4.
                process_fifo();
        }
-       if (toccata_active && (toccata_status & STATUS_FIFO_CODEC)) {
-               int old = toccata_irq;
-               if ((fifo_half & STATUS_FIFO_PLAY) && (toccata_status & STATUS_PLAY_INTENA) && (toccata_status & STATUS_FIFO_PLAY)) {
-                       toccata_irq |= STATUS_READ_PLAY_HALF;
+       if (data->toccata_active && (data->toccata_status & STATUS_FIFO_CODEC)) {
+               int old = data->toccata_irq;
+               if ((data->fifo_half & STATUS_FIFO_PLAY) && (data->toccata_status & STATUS_PLAY_INTENA) && (data->toccata_status & STATUS_FIFO_PLAY)) {
+                       data->toccata_irq |= STATUS_READ_PLAY_HALF;
                }
-               if ((fifo_half & STATUS_FIFO_RECORD) && (toccata_status & STATUS_FIFO_RECORD) && (toccata_status & STATUS_FIFO_RECORD)) {
-                       toccata_irq |= STATUS_READ_RECORD_HALF;
+               if ((data->fifo_half & STATUS_FIFO_RECORD) && (data->toccata_status & STATUS_FIFO_RECORD) && (data->toccata_status & STATUS_FIFO_RECORD)) {
+                       data->toccata_irq |= STATUS_READ_RECORD_HALF;
                }
-               if (old != toccata_irq) {
+               if (old != data->toccata_irq) {
                        sndboard_rethink();
 #if DEBUG_TOCCATA > 2
                        write_log(_T("TOCCATA IRQ\n"));
 #endif
                }
        }
-       audio_state_sndboard_state(ch, ch_sample[ch], event_time);
+       audio_state_sndboard_state(ch, data->ch_sample[ch], data->event_time);
 }
 
 static int get_volume(uae_u8 v)
@@ -167,27 +177,24 @@ static int get_volume_in(uae_u8 v)
        return out;
 }
 
-static void calculate_volume(void)
+static void calculate_volume_toccata(void)
 {
-       left_volume = get_volume(ad1848_regs[6]);
-       right_volume = get_volume(ad1848_regs[7]);
-       left_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
-       right_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
+       struct toccata_data *data = &toccata;
+       data->left_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
+       data->right_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
+
+       data->left_volume = get_volume(data->ad1848_regs[6]) * data->left_volume / 32768;
+       data->right_volume = get_volume(data->ad1848_regs[7]) * data->right_volume / 32768;
 
        if (currprefs.sound_toccata_mixer) {
-               sound_paula_volume[0] = get_volume_in(ad1848_regs[4]);
-               sound_paula_volume[1] = get_volume_in(ad1848_regs[5]);
+               sound_paula_volume[0] = get_volume_in(data->ad1848_regs[4]);
+               sound_paula_volume[1] = get_volume_in(data->ad1848_regs[5]);
 
-               sound_cd_volume[0] = get_volume_in(ad1848_regs[2]);
-               sound_cd_volume[1] = get_volume_in(ad1848_regs[3]);
+               sound_cd_volume[0] = get_volume_in(data->ad1848_regs[2]);
+               sound_cd_volume[1] = get_volume_in(data->ad1848_regs[3]);
        }
 }
 
-void sndboard_ext_volume(void)
-{
-       calculate_volume();
-}
-
 static const int freq_crystals[] = {
        // AD1848 documentation says 24.576MHz but photo of board shows 24.582MHz
        24582000,
@@ -206,17 +213,18 @@ static const int freq_dividers[] = {
 
 static void codec_setup(void)
 {
-       uae_u8 c = ad1848_regs[8];
-
-       channels = (c & 0x10) ? 2 : 1;
-       samplebits = (c & 0x40) ? 16 : 8;
-       freq = freq_crystals[c & 1] / freq_dividers[(c >> 1) & 7];
-       freq_adjusted = ((freq + 49) / 100) * 100;
-       bytespersample = (samplebits / 8) * channels;
+       struct toccata_data *data = &toccata;
+       uae_u8 c = data->ad1848_regs[8];
+
+       data->channels = (c & 0x10) ? 2 : 1;
+       data->samplebits = (c & 0x40) ? 16 : 8;
+       data->freq = freq_crystals[c & 1] / freq_dividers[(c >> 1) & 7];
+       data->freq_adjusted = ((data->freq + 49) / 100) * 100;
+       data->bytespersample = (data->samplebits / 8) * data->channels;
        write_log(_T("TOCCATA start %s freq=%d bits=%d channels=%d\n"),
-               ((toccata_active & (STATUS_FIFO_PLAY | STATUS_FIFO_RECORD)) == (STATUS_FIFO_PLAY | STATUS_FIFO_RECORD)) ? _T("Play+Record") :
-               (toccata_active & STATUS_FIFO_PLAY) ? _T("Play") : _T("Record"),
-               freq, samplebits, channels);
+               ((data->toccata_active & (STATUS_FIFO_PLAY | STATUS_FIFO_RECORD)) == (STATUS_FIFO_PLAY | STATUS_FIFO_RECORD)) ? _T("Play+Record") :
+               (data->toccata_active & STATUS_FIFO_PLAY) ? _T("Play") : _T("Record"),
+               data->freq, data->samplebits, data->channels);
 }
 
 static int capture_buffer_size = 48000 * 2 * 2; // 1s at 48000/stereo/16bit
@@ -225,28 +233,30 @@ static uae_u8 *capture_buffer;
 
 static void codec_start(void)
 {
-       toccata_active  = (ad1848_regs[9] & 1) ? STATUS_FIFO_PLAY : 0;
-       toccata_active |= (ad1848_regs[9] & 2) ? STATUS_FIFO_RECORD : 0;
+       struct toccata_data *data = &toccata;
+       data->toccata_active  = (data->ad1848_regs[9] & 1) ? STATUS_FIFO_PLAY : 0;
+       data->toccata_active |= (data->ad1848_regs[9] & 2) ? STATUS_FIFO_RECORD : 0;
 
        codec_setup();
 
-       event_time = base_event_clock * CYCLE_UNIT / freq;
-       record_event_time = base_event_clock * CYCLE_UNIT / (freq_adjusted * bytespersample);
-       record_event_counter = 0;
+       data->event_time = base_event_clock * CYCLE_UNIT / data->freq;
+       data->record_event_time = base_event_clock * CYCLE_UNIT / (data->freq_adjusted * data->bytespersample);
+       data->record_event_counter = 0;
 
-       if (toccata_active & STATUS_FIFO_PLAY) {
+       if (data->toccata_active & STATUS_FIFO_PLAY) {
                audio_enable_sndboard(true);
        }
-       if (toccata_active & STATUS_FIFO_RECORD) {
+       if (data->toccata_active & STATUS_FIFO_RECORD) {
                capture_buffer = xcalloc(uae_u8, capture_buffer_size);
-               sndboard_init_capture(freq_adjusted);
+               sndboard_init_capture(data->freq_adjusted);
        }
 }
 
 static void codec_stop(void)
 {
+       struct toccata_data *data = &toccata;
        write_log(_T("TOCCATA stop\n"));
-       toccata_active = 0;
+       data->toccata_active = 0;
        sndboard_free_capture();
        audio_enable_sndboard(false);
        xfree(capture_buffer);
@@ -255,12 +265,15 @@ static void codec_stop(void)
 
 void sndboard_rethink(void)
 {
-       if (toccata_irq)
-               INTREQ_0(0x8000 | 0x2000);
+       struct toccata_data *data = &toccata;
+       uae_int_requested &= ~0x200;
+       if (data->toccata_irq)
+               uae_int_requested |= 0x200;
 }
 
 static void sndboard_process_capture(void)
 {
+       struct toccata_data *data = &toccata;
        int frames;
        uae_u8 *buffer = sndboard_get_buffer(&frames);
        if (buffer && frames) {
@@ -282,63 +295,64 @@ static void sndboard_process_capture(void)
 
 void sndboard_hsync(void)
 {
+       struct toccata_data *data = &toccata;
        static int capcnt;
 
-       if (autocalibration > 0)
-               autocalibration--;
+       if (data->autocalibration > 0)
+               data->autocalibration--;
 
-       if (toccata_active & STATUS_FIFO_RECORD) {
+       if (data->toccata_active & STATUS_FIFO_RECORD) {
 
                capcnt--;
                if (capcnt <= 0) {
                        sndboard_process_capture();
-                       capcnt = record_event_time * 312 / (maxhpos * CYCLE_UNIT);
+                       capcnt = data->record_event_time * 312 / (maxhpos * CYCLE_UNIT);
                }
 
-               record_event_counter += maxhpos * CYCLE_UNIT;
-               int bytes = record_event_counter / record_event_time;
+               data->record_event_counter += maxhpos * CYCLE_UNIT;
+               int bytes = data->record_event_counter / data->record_event_time;
                bytes &= ~3;
                if (bytes < 64 || capture_read_index == capture_write_index)
                        return;
 
-               int oldfifo = data_in_record_fifo;
+               int oldfifo = data->data_in_record_fifo;
                int oldbytes = bytes;
-               int size = FIFO_SIZE - data_in_record_fifo;
+               int size = FIFO_SIZE - data->data_in_record_fifo;
                while (size > 0 && capture_read_index != capture_write_index && bytes > 0) {
-                       uae_u8 *fifop = &fifo[fifo_record_write_index];
+                       uae_u8 *fifop = &data->fifo[data->fifo_record_write_index];
                        uae_u8 *bufp = &capture_buffer[capture_read_index];
 
-                       if (samplebits == 8) {
+                       if (data->samplebits == 8) {
                                fifop[0] = bufp[1];
-                               fifo_record_write_index++;
-                               data_in_record_fifo++;
+                               data->fifo_record_write_index++;
+                               data->data_in_record_fifo++;
                                size--;
                                bytes--;
-                               if (channels == 2) {
+                               if (data->channels == 2) {
                                        fifop[1] = bufp[3];
-                                       fifo_record_write_index++;
-                                       data_in_record_fifo++;
+                                       data->fifo_record_write_index++;
+                                       data->data_in_record_fifo++;
                                        size--;
                                        bytes--;
                                }
-                       } else if (samplebits == 16) {
+                       } else if (data->samplebits == 16) {
                                fifop[0] = bufp[1];
                                fifop[1] = bufp[0];
-                               fifo_record_write_index += 2;
-                               data_in_record_fifo += 2;
+                               data->fifo_record_write_index += 2;
+                               data->data_in_record_fifo += 2;
                                size -= 2;
                                bytes -= 2;
-                               if (channels == 2) {
+                               if (data->channels == 2) {
                                        fifop[2] = bufp[3];
                                        fifop[3] = bufp[2];
-                                       fifo_record_write_index += 2;
-                                       data_in_record_fifo += 2;
+                                       data->fifo_record_write_index += 2;
+                                       data->data_in_record_fifo += 2;
                                        size -= 2;
                                        bytes -= 2;
                                }
                        }
 
-                       fifo_record_write_index %= FIFO_SIZE;
+                       data->fifo_record_write_index %= FIFO_SIZE;
                        capture_read_index += 4;
                        if (capture_read_index >= capture_buffer_size)
                                capture_read_index = 0;
@@ -346,25 +360,27 @@ void sndboard_hsync(void)
                
                write_log(_T("%d %d %d %d\n"), capture_read_index, capture_write_index, size, bytes);
 
-               if (data_in_record_fifo > FIFO_SIZE_HALF && oldfifo <= FIFO_SIZE_HALF) {
-                       fifo_half |= STATUS_FIFO_RECORD;
+               if (data->data_in_record_fifo > FIFO_SIZE_HALF && oldfifo <= FIFO_SIZE_HALF) {
+                       data->fifo_half |= STATUS_FIFO_RECORD;
                        audio_state_sndboard(-1);
                }
-               record_event_counter -= oldbytes * record_event_time;
+               data->record_event_counter -= oldbytes * data->record_event_time;
        }
 }
 
-void sndboard_vsync(void)
+static void sndboard_vsync_toccata(void)
 {
-       if (toccata_active) {
-               calculate_volume();
+       struct toccata_data *data = &toccata;
+       if (data->toccata_active) {
+               calculate_volume_toccata();
                audio_activate();
        }
 }
 
 static void toccata_put(uaecptr addr, uae_u8 v)
 {
-       int idx = ad1848_index & 15;
+       struct toccata_data *data = &toccata;
+       int idx = data->ad1848_index & 15;
 
 #if DEBUG_TOCCATA > 2
        if (addr & 0x4000)
@@ -373,11 +389,11 @@ static void toccata_put(uaecptr addr, uae_u8 v)
 
        if ((addr & 0x6801) == 0x6001) {
                // AD1848 register 0
-               ad1848_index = v;
+               data->ad1848_index = v;
        } else if ((addr & 0x6801) == 0x6801) {
                // AD1848 register 1
-               uae_u8 old = ad1848_regs[idx];
-               ad1848_regs[idx] = v;
+               uae_u8 old = data->ad1848_regs[idx];
+               data->ad1848_regs[idx] = v;
 #if DEBUG_TOCCATA > 0
                write_log(_T("TOCCATA PUT reg %d = %02x PC=%08x\n"), idx, v, M68K_GETPC);
 #endif
@@ -385,7 +401,7 @@ static void toccata_put(uaecptr addr, uae_u8 v)
                {
                        case 9:
                        if (v & 8) // ACI enabled
-                               autocalibration = 50;
+                               data->autocalibration = 50;
                        if (!(old & 3) && (v & 3))
                                codec_start();
                        else if ((old & 3) && !(v & 3))
@@ -399,40 +415,40 @@ static void toccata_put(uaecptr addr, uae_u8 v)
                        case 6:
                        case 7:
                        case 8:
-                               calculate_volume();
+                               calculate_volume_toccata();
                        break;
 
                }
        } else if ((addr & 0x6800) == 0x2000) {
                // FIFO input
-               if (toccata_status & STATUS_FIFO_PLAY) {
+               if (data->toccata_status & STATUS_FIFO_PLAY) {
                        // 7202LA datasheet says fifo can't overflow
-                       if (((fifo_write_index + 1) % FIFO_SIZE) != fifo_read_index) {
-                               fifo[fifo_write_index] = v;
-                               fifo_write_index++;
-                               fifo_write_index %= FIFO_SIZE;
-                               data_in_fifo++;
+                       if (((data->fifo_write_index + 1) % FIFO_SIZE) != data->fifo_read_index) {
+                               data->fifo[data->fifo_write_index] = v;
+                               data->fifo_write_index++;
+                               data->fifo_write_index %= FIFO_SIZE;
+                               data->data_in_fifo++;
                        }
                }
-               toccata_irq &= ~STATUS_READ_PLAY_HALF;
-               fifo_half &= ~STATUS_FIFO_PLAY;
+               data->toccata_irq &= ~STATUS_READ_PLAY_HALF;
+               data->fifo_half &= ~STATUS_FIFO_PLAY;
        } else if ((addr & 0x6800) == 0x0000) {
                // Board status
                if (v & STATUS_RESET) {
                        codec_stop();
-                       toccata_status = 0;
-                       toccata_irq = 0;
+                       data->toccata_status = 0;
+                       data->toccata_irq = 0;
                        v = 0;
                }
                if (v == STATUS_ACTIVE) {
-                       fifo_write_index = 0;
-                       fifo_read_index = 0;
-                       data_in_fifo = 0;
-                       toccata_status = 0;
-                       toccata_irq = 0;
-                       fifo_half = 0;
+                       data->fifo_write_index = 0;
+                       data->fifo_read_index = 0;
+                       data->data_in_fifo = 0;
+                       data->toccata_status = 0;
+                       data->toccata_irq = 0;
+                       data->fifo_half = 0;
                }
-               toccata_status = v;
+               data->toccata_status = v;
 #if DEBUG_TOCCATA > 0
                write_log(_T("TOCCATA PUT STATUS %08x %02x %d PC=%08X\n"), addr, v, idx, M68K_GETPC);
 #endif
@@ -443,25 +459,26 @@ static void toccata_put(uaecptr addr, uae_u8 v)
 
 static uae_u8 toccata_get(uaecptr addr)
 {
-       int idx = ad1848_index & 15;
+       struct toccata_data *data = &toccata;
+       int idx = data->ad1848_index & 15;
        uae_u8 v = 0;
 
        if ((addr & 0x6801) == 0x6001) {
                // AD1848 register 0
-               v = ad1848_index;
+               v = data->ad1848_index;
        } else if ((addr & 0x6801) == 0x6801) {
                // AD1848 register 1
-               v = ad1848_regs[idx];
+               v = data->ad1848_regs[idx];
 #if DEBUG_TOCCATA > 0
                write_log(_T("TOCCATA GET reg %d = %02x PC=%08x\n"), idx, v, M68K_GETPC);
 #endif
                switch (idx)
                {
                        case 11:
-                       if (autocalibration > 10 && autocalibration < 30)
-                               ad1848_regs[11] |= 0x20;
+                       if (data->autocalibration > 10 && data->autocalibration < 30)
+                               data->ad1848_regs[11] |= 0x20;
                        else
-                               ad1848_regs[11] &= ~0x20;
+                               data->ad1848_regs[11] &= ~0x20;
                        break;
                        case 12:
                                // revision
@@ -470,23 +487,23 @@ static uae_u8 toccata_get(uaecptr addr)
                }
        } else if ((addr & 0x6800) == 0x2000) {
                // FIFO output
-               v = fifo[fifo_record_read_index];
-               if (toccata_status & STATUS_FIFO_RECORD) {
-                       if (data_in_record_fifo > 0) {
-                               fifo_record_read_index++;
-                               fifo_record_read_index %= FIFO_SIZE;
-                               data_in_record_fifo--;
+               v = data->fifo[data->fifo_record_read_index];
+               if (data->toccata_status & STATUS_FIFO_RECORD) {
+                       if (data->data_in_record_fifo > 0) {
+                               data->fifo_record_read_index++;
+                               data->fifo_record_read_index %= FIFO_SIZE;
+                               data->data_in_record_fifo--;
                        }
                }
-               toccata_irq &= ~STATUS_READ_RECORD_HALF;
-               fifo_half &= ~STATUS_FIFO_RECORD;
+               data->toccata_irq &= ~STATUS_READ_RECORD_HALF;
+               data->fifo_half &= ~STATUS_FIFO_RECORD;
        } else if ((addr & 0x6800) == 0x0000) {
                // Board status
                v = STATUS_READ_INTREQ; // active low
-               if (toccata_irq) {
+               if (data->toccata_irq) {
                        v &= ~STATUS_READ_INTREQ;
-                       v |= toccata_irq;
-                       toccata_irq = 0;
+                       v |= data->toccata_irq;
+                       data->toccata_irq = 0;
                }
 #if DEBUG_TOCCATA > 0
                write_log(_T("TOCCATA GET STATUS %08x %02x %d PC=%08X\n"), addr, v, idx, M68K_GETPC);
@@ -503,27 +520,28 @@ static uae_u8 toccata_get(uaecptr addr)
 
 static void REGPARAM2 toccata_bput(uaecptr addr, uae_u32 b)
 {
+       struct toccata_data *data = &toccata;
 #ifdef JIT
        special_mem |= S_WRITE;
 #endif
        b &= 0xff;
        addr &= BOARD_MASK;
-       if (!configured) {
+       if (!data->configured) {
                switch (addr)
                {
                        case 0x48:
                        map_banks_z2(&toccata_bank, expamem_z2_pointer >> 16, BOARD_SIZE >> 16);
-                       configured = 1;
+                       data->configured = 1;
                        expamem_next(&toccata_bank, NULL);
                        break;
                        case 0x4c:
-                       configured = -1;
+                       data->configured = -1;
                        expamem_shutup(&toccata_bank);
                        break;
                }
                return;
        }
-       if (configured > 0)
+       if (data->configured > 0)
                toccata_put(addr, b);
 }
 
@@ -549,17 +567,18 @@ static void REGPARAM2 toccata_lput(uaecptr addr, uae_u32 b)
 
 static uae_u32 REGPARAM2 toccata_bget(uaecptr addr)
 {
+       struct toccata_data *data = &toccata;
        uae_u8 v = 0;
 #ifdef JIT
        special_mem |= S_READ;
 #endif
        addr &= BOARD_MASK;
-       if (!configured) {
-               if (addr >= sizeof acmemory)
+       if (!data->configured) {
+               if (addr >= sizeof data->acmemory)
                        return 0;
-               return acmemory[addr];
+               return data->acmemory[addr];
        }
-       if (configured > 0)
+       if (data->configured > 0)
                v = toccata_get(addr);
        return v;
 }
@@ -593,7 +612,7 @@ addrbank toccata_bank = {
        dummy_lgeti, dummy_wgeti, ABFLAG_IO
 };
 
-static void ew (int addr, uae_u32 value)
+static void ew (uae_u8 *acmemory, int addr, uae_u32 value)
 {
        addr &= 0xffff;
        if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
@@ -607,38 +626,618 @@ static void ew (int addr, uae_u32 value)
 
 addrbank *sndboard_init(int devnum)
 {
-       memset(ad1848_regs, 0, sizeof ad1848_regs);
-       ad1848_regs[2] = 0x80;
-       ad1848_regs[3] = 0x80;
-       ad1848_regs[4] = 0x80;
-       ad1848_regs[5] = 0x80;
-       ad1848_regs[6] = 0x80;
-       ad1848_regs[7] = 0x80;
-       ad1848_regs[9] = 0x10;
-       ad1848_status = 0xcc;
-       ad1848_index = 0x40;
-       calculate_volume();
-
-       configured = 0;
-       memset(acmemory, 0xff, sizeof acmemory);
+       struct toccata_data *data = &toccata;
+       memset(data->ad1848_regs, 0, sizeof data->ad1848_regs);
+       data->ad1848_regs[2] = 0x80;
+       data->ad1848_regs[3] = 0x80;
+       data->ad1848_regs[4] = 0x80;
+       data->ad1848_regs[5] = 0x80;
+       data->ad1848_regs[6] = 0x80;
+       data->ad1848_regs[7] = 0x80;
+       data->ad1848_regs[9] = 0x10;
+       data->ad1848_status = 0xcc;
+       data->ad1848_index = 0x40;
+       calculate_volume_toccata();
+
+       data->configured = 0;
+       memset(data->acmemory, 0xff, sizeof data->acmemory);
        for (int i = 0; i < 16; i++) {
                uae_u8 b = toccata_autoconfig[i];
-               ew(i * 4, b);
+               ew(data->acmemory, i * 4, b);
        }
        return &toccata_bank;
 }
 
 void sndboard_free(void)
 {
+       struct toccata_data *data = &toccata;
+       data->toccata_irq = 0;
+       uae_int_requested &= ~0x200;
 }
 
 void sndboard_reset(void)
 {
-       ch_sample[0] = 0;
-       ch_sample[1] = 0;
+       struct toccata_data *data = &toccata;
+       data->ch_sample[0] = 0;
+       data->ch_sample[1] = 0;
+       audio_enable_sndboard(false);
+}
+
+struct fm801_data
+{
+       struct pci_board_state *pcibs;
+       uaecptr play_dma[2], play_dma2[2];
+       uae_u16 play_len, play_len2;
+       uae_u16 play_control;
+       uae_u16 interrupt_control;
+       uae_u16 interrupt_status;
+       int dmach;
+       int freq;
+       int bits;
+       int ch;
+       int bytesperframe;
+       bool play_on;
+       int left_volume, right_volume;
+       int ch_sample[2];
+       int event_time;
+};
+static struct fm801_data fm801;
+static bool fm801_active;
+static const int fm801_freq[16] = { 5500, 8000, 9600, 11025, 16000, 19200, 22050, 32000, 38400, 44100, 48000 };
+
+static void calculate_volume_fm801(void)
+{
+       struct fm801_data *data = &fm801;
+       data->left_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
+       data->right_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
+}
+
+static void sndboard_vsync_fm801(void)
+{
+       audio_activate();
+       calculate_volume_fm801();
+}
+
+static void fm801_stop(struct fm801_data *data)
+{
+       write_log(_T("FM801 STOP\n"));
+       data->play_on = false;
        audio_enable_sndboard(false);
 }
 
+static void fm801_swap_buffers(struct fm801_data *data)
+{
+       data->dmach = data->dmach ? 0 : 1;
+       data->play_dma2[data->dmach] = data->play_dma[data->dmach];
+       data->play_len2 = data->play_len;
+       // stop at the end of buffer
+       if (!(data->play_control & 0x20) && !(data->play_control & 0x80))
+               fm801_stop(data);
+}
+
+static void fm801_interrupt(struct fm801_data *data)
+{
+       if ((data->interrupt_status & 0x100) && !(data->interrupt_control & 1)) {
+               data->pcibs->board->irq(data->pcibs, true);
+       } else {
+               data->pcibs->board->irq(data->pcibs, false);
+       }
+}
+
+static void audio_state_sndboard_fm801(int ch)
+{
+       struct fm801_data *data = &fm801;
+
+       if (data->play_on && ch == 0) {
+               uae_u8 sample[2 * 6] = { 0 };
+               uae_s16 l, r;
+               pci_read_dma(data->pcibs, data->play_dma2[data->dmach], sample, data->bytesperframe);
+               if (data->bits == 8) {
+                       if (data->ch == 1) {
+                               sample[1] = sample[0];
+                               sample[2] = sample[0];
+                               sample[3] = sample[0];
+                       } else {
+                               sample[2] = sample[1];
+                               sample[3] = sample[1];
+                               sample[1] = sample[0];
+                       }
+               } else {
+                       if (data->ch == 1) {
+                               sample[2] = sample[0];
+                               sample[3] = sample[1];
+                       }
+               }
+               l = (sample[1] << 8) | sample[0];
+               r = (sample[3] << 8) | sample[2];
+               data->ch_sample[0] = l;
+               data->ch_sample[1] = r;
+               data->ch_sample[0] = data->ch_sample[0] * data->left_volume / 32768;
+               data->ch_sample[1] = data->ch_sample[1] * data->right_volume / 32768;
+
+               data->play_len2 -= data->bytesperframe;
+               data->play_dma2[data->dmach] += data->bytesperframe;
+               if (data->play_len2 == 0xffff) {
+                       fm801_swap_buffers(data);
+                       data->interrupt_status |= 0x100;
+                       fm801_interrupt(data);
+               }
+       }
+       audio_state_sndboard_state(ch, data->ch_sample[ch], data->event_time);
+}
+
+static void fm801_hsync_handler(struct pci_board_state *pcibs)
+{
+}
+
+static void fm801_play(struct fm801_data *data)
+{
+       uae_u16 control = data->play_control;
+       int f = (control >> 8) & 15;
+       data->freq = fm801_freq[f];
+       if (!data->freq)
+               data->freq = 44100;
+       data->event_time = base_event_clock * CYCLE_UNIT / data->freq;
+       data->bits = (control & 0x4000) ? 16 : 8;
+       f = (control >> 12) & 3;
+       switch (f)
+       {
+               case 0:
+               data->ch = (control & 0x8000) ? 2 : 1;
+               break;
+               case 1:
+               data->ch = 4;
+               break;
+               case 2:
+               data->ch = 6;
+               break;
+               case 3:
+               data->ch = 6;
+               break;
+       }
+       data->bytesperframe = data->bits * data->ch / 8;
+       data->play_on = true;
+
+       data->dmach = 1;
+       fm801_swap_buffers(data);
+
+       calculate_volume_fm801();
+
+       write_log(_T("FM801 PLAY: freq=%d ch=%d bits=%d\n"), data->freq, data->ch, data->bits);
+
+       audio_enable_sndboard(true);
+}
+
+static void fm801_pause(struct fm801_data *data, bool pause)
+{
+       write_log(_T("FM801 PAUSED %d\n"), pause);
+}
+static void fm801_control(struct fm801_data *data, uae_u16 control)
+{
+       uae_u16 old_control = data->play_control;
+       data->play_control = control;
+       data->play_control &= ~(8 | 16);
+       if ((data->play_control & 0x20) && !(old_control & 0x20)) {
+               fm801_play(data);
+       } else if (!(data->play_control & 0x20) && (old_control & 0x20)) {
+               if (data->play_control & 0x80)
+                       fm801_stop(data);
+       } else if (data->play_control & 0x20) {
+               if ((data->play_control & 0x40) && !(old_control & 0x40)) {
+                       fm801_pause(data, true);
+               } else if (!(data->play_control & 0x40) && (old_control & 0x40)) {
+                       fm801_pause(data, true);
+               }
+       }
+
+}
+
+static void REGPARAM2 fm801_bput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       struct fm801_data *data = &fm801;
+}
+static void REGPARAM2 fm801_wput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       struct fm801_data *data = &fm801;
+       switch (addr)
+       {
+               case 0x08:
+               fm801_control(data, b);
+               break;
+               case 0x0a:
+               data->play_len = b;
+               break;
+               case 0x56:
+               data->interrupt_control = b;
+               fm801_interrupt(data);
+               break;
+               case 0x5a:
+               data->interrupt_status &= ~b;
+               fm801_interrupt(data);
+               break;
+       }
+}
+static void REGPARAM2 fm801_lput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       struct fm801_data *data = &fm801;
+       switch (addr)
+       {
+               case 0x0c:
+               data->play_dma[0] = b;
+               break;
+               case 0x10:
+               data->play_dma[1] = b;
+               break;
+       }
+}
+static uae_u32 REGPARAM2 fm801_bget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       struct fm801_data *data = &fm801;
+       uae_u32 v = 0;
+       return v;
+}
+static uae_u32 REGPARAM2 fm801_wget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       struct fm801_data *data = &fm801;
+       uae_u32 v = 0;
+       switch (addr) {
+               case 0x08:
+               v = data->play_control;
+               break;
+               case 0x0a:
+               v = data->play_len2;
+               break;
+               case 0x56:
+               v = data->interrupt_control;
+               break;
+               case 0x5a:
+               v = data->interrupt_status;
+               break;
+
+       }
+       return v;
+}
+static uae_u32 REGPARAM2 fm801_lget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       struct fm801_data *data = &fm801;
+       uae_u32 v = 0;
+       switch(addr)
+       {
+               case 0x0c:
+               v = data->play_dma2[data->dmach];
+               break;
+               case 0x10:
+               v = data->play_dma2[data->dmach];
+               break;
+       }
+       return v;
+}
+
+static void fm801_reset(struct pci_board_state *pcibs)
+{
+       struct fm801_data *data = &fm801;
+       data->play_control = 0xca00;
+       data->interrupt_control = 0x00df;
+}
+
+static void fm801_free(struct pci_board_state *pcibs)
+{
+       struct fm801_data *data = &fm801;
+       fm801_active = false;
+       fm801_stop(data);
+}
+
+static bool fm801_init(struct pci_board_state *pcibs)
+{
+       struct fm801_data *data = &fm801;
+       memset(data, 0, sizeof(struct fm801_data));
+       data->pcibs = pcibs;
+       fm801_active = true;
+       return false;
+}
+
+static const struct pci_config fm801_pci_config =
+{
+       0x1319, 0x0801, 0, 0, 0xb2, 0x040100, 0x80, 0x1319, 0x1319, 1, 0x04, 0x28, { 128 | 1, 0, 0, 0, 0, 0, 0 }
+};
+static const struct pci_config fm801_pci_config_func1 =
+{
+       0x1319, 0x0802, 0, 0, 0xb2, 0x098000, 0x80, 0x1319, 0x1319, 0, 0x04, 0x28, { 16 | 1, 0, 0, 0, 0, 0, 0 }
+};
+
+const struct pci_board fm801_pci_board =
+{
+       _T("FM801"),
+       &fm801_pci_config, fm801_init, fm801_free, fm801_reset, fm801_hsync_handler, pci_irq_callback,
+       {
+               { fm801_lget, fm801_wget, fm801_bget, fm801_lput, fm801_wput, fm801_bput },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+       }
+};
+
+const struct pci_board fm801_pci_board_func1 =
+{
+       _T("FM801-2"),
+       &fm801_pci_config_func1, NULL, NULL, NULL, NULL, NULL,
+       {
+               { fm801_lget, fm801_wget, fm801_bget, fm801_lput, fm801_wput, fm801_bput },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+               { NULL },
+       }
+};
+
+static void solo1_reset(struct pci_board_state *pcibs)
+{
+}
+
+static void solo1_free(struct pci_board_state *pcibs)
+{
+}
+
+static bool solo1_init(struct pci_board_state *pcibs)
+{
+       return true;
+}
+
+static void solo1_sb_put(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+}
+static uae_u32 solo1_sb_get(struct pci_board_state *pcibs, uaecptr addr)
+{
+       uae_u32 v = 0;
+       return v;
+}
+
+static void solo1_put(struct pci_board_state *pcibs, int bar, uaecptr addr, uae_u32 b)
+{
+       if (bar == 1)
+               solo1_sb_put(pcibs, addr, b);
+}
+static uae_u32 solo1_get(struct pci_board_state *pcibs, int bar, uaecptr addr)
+{
+       uae_u32 v = 0;
+       if (bar == 1)
+               v = solo1_sb_get(pcibs, addr);
+       return v;
+}
+
+static void REGPARAM2 solo1_bput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       write_log(_T("SOLO1 BPUT %08x=%08x %d\n"), addr, b, pcibs->selected_bar);
+       solo1_put(pcibs, pcibs->selected_bar, addr + 0, b >> 24);
+       solo1_put(pcibs, pcibs->selected_bar, addr + 1, b >> 16);
+       solo1_put(pcibs, pcibs->selected_bar, addr + 2, b >>  8);
+       solo1_put(pcibs, pcibs->selected_bar, addr + 3, b >>  0);
+}
+static void REGPARAM2 solo1_wput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       write_log(_T("SOLO1 WPUT %08x=%08x %d\n"), addr, b, pcibs->selected_bar);
+       solo1_put(pcibs, pcibs->selected_bar, addr + 0, b >> 8);
+       solo1_put(pcibs, pcibs->selected_bar, addr + 1, b >> 0);
+}
+static void REGPARAM2 solo1_lput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
+{
+       write_log(_T("SOLO1 LPUT %08x=%08x %d\n"), addr, b, pcibs->selected_bar);
+       solo1_put(pcibs, pcibs->selected_bar, addr, b);
+}
+static uae_u32 REGPARAM2 solo1_bget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       uae_u32 v = 0;
+       v = solo1_get(pcibs, pcibs->selected_bar, addr);
+       write_log(_T("SOLO1 BGET %08x %d\n"), addr, pcibs->selected_bar);
+       return v;
+}
+static uae_u32 REGPARAM2 solo1_wget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       uae_u32 v = 0;
+       write_log(_T("SOLO1 WGET %08x %d\n"), addr, pcibs->selected_bar);
+       return v;
+}
+static uae_u32 REGPARAM2 solo1_lget(struct pci_board_state *pcibs, uaecptr addr)
+{
+       uae_u32 v = 0;
+       write_log(_T("SOLO1 LGET %08x %d\n"), addr, pcibs->selected_bar);
+       return v;
+}
+
+static const struct pci_config solo1_pci_config =
+{
+       0x125d, 0x1969, 0, 0, 0, 0x040100, 0, 0x125d, 0x1818, 1, 2, 0x18, { 16 | 1, 16 | 1, 16 | 1, 4 | 1, 4 | 1, 0, 0 }
+};
+const struct pci_board solo1_pci_board =
+{
+       _T("SOLO1"),
+       &solo1_pci_config, solo1_init, solo1_free, solo1_reset, NULL, pci_irq_callback,
+       {
+               { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
+               { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
+               { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
+               { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
+               { solo1_lget, solo1_wget, solo1_bget, solo1_lput, solo1_wput, solo1_bput },
+               { NULL },
+               { NULL },
+       }
+};
+
+static SWVoiceOut *qemu_voice_out;
+
+static void calculate_volume_qemu(void)
+{
+       SWVoiceOut *out = qemu_voice_out;
+       if (!out)
+               return;
+       out->left_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
+       out->right_volume = (100 - currprefs.sound_volume_board) * 32768 / 100;
+}
+
+void AUD_close_in(QEMUSoundCard *card, SWVoiceIn *sw)
+{
+}
+int AUD_read(SWVoiceIn *sw, void *pcm_buf, int size)
+{
+       return size;
+}
+int AUD_write(SWVoiceOut *sw, void *pcm_buf, int size)
+{
+       memcpy(sw->samplebuf, pcm_buf, size);
+       sw->samplebuf_total = size;
+       return sw->samplebuf_total;
+}
+void AUD_set_active_out(SWVoiceOut *sw, int on)
+{
+       sw->active = on != 0;
+       sw->event_time = base_event_clock * CYCLE_UNIT / sw->freq;
+       sw->samplebuf_index = 0;
+       sw->samplebuf_total = 0;
+       calculate_volume_qemu();
+       audio_enable_sndboard(sw->active);
+}
+void AUD_set_active_in(SWVoiceIn *sw, int on)
+{
+}
+int  AUD_is_active_in(SWVoiceIn *sw)
+{
+       return 0;
+}
+void AUD_close_out(QEMUSoundCard *card, SWVoiceOut *sw)
+{
+       qemu_voice_out = NULL;
+       audio_enable_sndboard(false);
+       xfree(sw);
+}
+SWVoiceIn *AUD_open_in(
+       QEMUSoundCard *card,
+       SWVoiceIn *sw,
+       const char *name,
+       void *callback_opaque,
+       audio_callback_fn callback_fn,
+struct audsettings *settings)
+{
+       return NULL;
+}
+SWVoiceOut *AUD_open_out(
+       QEMUSoundCard *card,
+       SWVoiceOut *sw,
+       const char *name,
+       void *callback_opaque,
+       audio_callback_fn callback_fn,
+       struct audsettings *settings)
+{
+       SWVoiceOut *out = sw;
+       if (!sw)
+               out = xcalloc(SWVoiceOut, 1);
+       int bits = 8;
+
+       if (settings->fmt >= AUD_FMT_U16)
+               bits = 16;
+       if (settings->fmt >= AUD_FMT_U32)
+               bits = 32;
+
+       out->callback = callback_fn;
+       out->opaque = callback_opaque;
+       out->bits = bits;
+       out->freq = settings->freq;
+       out->ch = settings->nchannels;
+       out->fmt = settings->fmt;
+       out->bytesperframe = out->ch * bits / 8;
+
+       write_log(_T("QEMU AUDIO: freq=%d ch=%d bits=%d (fmt=%d) '%s'\n"), out->freq, out->ch, bits, settings->fmt, name);
+
+       qemu_voice_out = out;
+
+       return out;
+}
+
+static void audio_state_sndboard_qemu(int ch)
+{
+       SWVoiceOut *out = qemu_voice_out;
+
+       if (!out)
+               return;
+       if (out->active && ch == 0) {
+               uae_s16 l, r;
+               if (out->samplebuf_index >= out->samplebuf_total) {
+                       int maxsize = sizeof(out->samplebuf);
+                       int size = 128 * out->bytesperframe;
+                       if (size > maxsize)
+                               size = maxsize;
+                       out->callback(out->opaque, size);
+                       out->samplebuf_index = 0;
+               }
+               uae_u8 *p = out->samplebuf + out->samplebuf_index;
+               if (out->bits == 8) {
+                       if (out->ch == 1) {
+                               p[1] = p[0];
+                               p[2] = p[0];
+                               p[3] = p[0];
+                       } else {
+                               p[2] = p[1];
+                               p[3] = p[1];
+                               p[1] = p[0];
+                       }
+               } else {
+                       if (out->ch == 1) {
+                               p[2] = p[0];
+                               p[3] = p[1];
+                       }
+               }
+               l = (p[1] << 8) | p[0];
+               r = (p[3] << 8) | p[2];
+               out->ch_sample[0] = l;
+               out->ch_sample[1] = r;
+               out->ch_sample[0] = out->ch_sample[0] * out->left_volume / 32768;
+               out->ch_sample[1] = out->ch_sample[1] * out->right_volume / 32768;
+               out->samplebuf_index += out->bytesperframe;
+       }
+       audio_state_sndboard_state(ch, out->ch_sample[ch], out->event_time);
+}
+
+
+static void sndboard_vsync_qemu(void)
+{
+       audio_activate();
+}
+
+
+void audio_state_sndboard(int ch)
+{
+       if (toccata.toccata_active)
+               audio_state_sndboard_toccata(ch);
+       if (fm801_active)
+               audio_state_sndboard_fm801(ch);
+       if (qemu_voice_out && qemu_voice_out->active)
+               audio_state_sndboard_qemu(ch);
+}
+
+void sndboard_vsync(void)
+{
+       if (toccata.toccata_active)
+               sndboard_vsync_toccata();
+       if (fm801_active)
+               sndboard_vsync_fm801();
+       if (qemu_voice_out && qemu_voice_out->active)
+               sndboard_vsync_qemu();
+}
+
+void sndboard_ext_volume(void)
+{
+       if (toccata.toccata_active)
+               calculate_volume_toccata();
+       if (fm801_active)
+               calculate_volume_fm801();
+       if (qemu_voice_out && qemu_voice_out->active)
+               calculate_volume_qemu();
+}
+
 #ifdef _WIN32
 
 #include <mmdeviceapi.h>