[VM][FMTOWNS][TODO] Will add TONWS::MIXER() class.
Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
Date : 2019.01.29-
- [ADC AD7820KR with FIFO]
+ [ADC AD7820KR]
*/
#include "../../common.h"
#include "ad7820kr.h"
+#define EVENT_SAMPLE 1
+
void AD7820KR::initialize()
{
// ADC
- adc_fifo->clear();
- adc_data = 0x00;
+ write_signals(&outputs_intr, 0x00);
+ write_signals(&outputs_overflow, 0x00);
+ write_signals(&outputs_ready, 0xffffffff);
+ event_sample = -1;
}
void AD7820KR::release()
{
- adc_fifo->release();
}
void AD7820KR::reset()
{
- // ToDo: IS CLEAR FIFO?
- initialize_sampler(in_rate, out_rate);
+ // Q: OK?
+ //if(event_sample >= 0) {
+ /// cancel_event(this, event_sample);
+ //}
+ //event_sample = -1;
+ prev_clock = get_current_clock();
}
uint32_t AD7820KR::read_signal(int ch)
{
- if(ch == SIG_AD7820_POP_FIFO) {
- if(adc_fifo->empty()) {
- return 0x00;
- }
- return (uint32_t)(adc_fifo->read() & 0xff);
- } else if(ch == SIG_AD7820_PEEK_FIFO) {
- if(adc_fifo->empty()) {
- return 0x00;
+ if(ch == SIG_AD7820_DATA_REG) {
+ if(cs_enabled) {
+ if(!(wr_rd_mode) && (req_convert)) {
+ if(event_sample < 0) {
+ start_sample(2.50);
+ req_convert = false;
+ }
+ }
+ return (uint32_t)adc_data;
+ } else {
+ return 0xff;
}
- return (uint32_t)(adc_fifo->read_not_remove() & 0xff);
- } else if(ch == SIG_AD7820_FIFO_IS_EMPTY) {
- return ((adc_fifo->empty()) ? 0x00 : 0xffffffff);
+ } else if(ch == SIG_AD7820_SAMPLE_RATE) {
+ return (uint32_t)this_sample_rate;
}
- return 0x00;
+ return 0;
}
-void AD7820KR::push_fifo(uint32_t data)
+void AD7820KR::event_callback(int event_id, int err)
{
- if(in_fifo->full()) {
- in_fifo->read(); // Dummy read OK?
+ if(event_id == EVENT_SAMPLE) {
+ event_sample = -1;
+ uint32_t passed_usec = get_passed_usec(prev_clock);
+ prev_clock = get_current_clock();
+ int in_rate = get_sound_in_rate(this_bank);
+ int in_samples = get_sound_in_samples(this_bank);
+ double max_usec = (1.0e6 / (double)in_rate) * (double)in_samples;
+ req_convert = false;
+ write_signals(&outputs_ready, 0xffffffff); // SAMPLING END
+ if(passed_usec >= 0.0f) {
+ if(passed_usec >= max_usec) {
+ passed_usec = max_usec;
+ }
+ bool overflow = false;
+ if(!(passed_usec < (1.0e6 / (double)this_sample_rate))) {
+ int32_t buffer[2];
+ increment_sound_in_passed_data(this_bank, passed_usec);
+ int gotsize = get_sound_in_data(this_bank, buffer, 1, this_sample_rate, 1);
+ if(gotsize > 0) {
+ int32_t _n = tmpbuf[gotsize - 1];
+ if(_n >= 16383) { // OVERFLOW
+ overflow = true;
+ _n = 16383;
+ } else if(_n <= -16384) {
+ overflow = true;
+ _n = -16384;
+ }
+ _n = _n / 128;
+ _n = _n + 128;
+ if(wr_rd_mode) {
+ adc_data = ((adc_msb & 0xf0) | (_n & 0x0f));
+ } else {
+ adc_data = _n & 0xff;
+ }
+ adc_msb = _n & 0xf0;
+ write_signals(&outputs_overflow, (overflow) ? 0xffffffff : 0x00000000); // Write OVERFLOW.
+ }
+ }
+ }
+ write_signals(&outputs_intr, 0xffffffff); // Write INT.
}
- in_fifo->write((int)(data & 0xff));
+}
+
+void AD7820KR::start_sample(double usec)
+{
+ write_signals(&outputs_ready, 0x00000000); // IN SAMPLING
+ write_signals(&outputs_intr, 0x00000000); // CLEAR INTRRUPT
+ write_signals(&outputs_overflow, 0x00000000); // CLEAR OVERFLOW
+ register_event(this, EVENT_SAMPLE, usec, false, &event_sample);
}
void AD7820KR::write_signal(int ch, uint32_t data, uint32_t mask)
{
+ bool f;
switch(ch)
{
case SIG_AD7820_RESET:
- initialize_sampler(in_rate, out_rate);
+ adc_data = 0x00; // Is reset
+ adc_msb = 0x00;
+ //wr_rd_mode = false; // HOLD
+ //req_convert = false; // HOLD
+ if(event_sample >= 0) {
+ cancel_event(this, event_sample);
+ event_sample = -1;
+ }
+ write_signals(&outputs_intr, 0x00);
+ write_signals(&outputs_overflow, 0x00);
+ write_signals(&outputs_ready, 0xffffffff);
break;
- case SIG_AD7820_DO_SAMPLE:
- push_fifo(data);
+ case SIG_AD7820_SET_SAMPLE_MODE:
+ wr_rd_mode = ((data & mask) != 0) ? true : false;
break;
- case SIG_AD7820_PERIOD_OUT:
- if(in_rate > out_rate) {
- out_mod = 0;
- out_count = 1;
- int local_count = in_rate / out_rate;
- int local_mod = in_rate % out_rate;
- if(in_fifo->empty()) {
- adc_data = 0x00;
- } else {
- for(uint32_t i = 0; i < local_count; i++) {
- if(in_fifo->empty()) break;
- adc_data = (uint8_t)(in_fifo->read() & 0xff);
- }
- in_mod = in_mod + local_mod;
- if(in_mod >= out_rate) {
- if(!(in_fifo->empty())) {
- adc_data = (uint8_t)(in_fifo->read() & 0xff);
- }
- in_mod -= out_rate;
- }
- write_signals(&output_data, adc_data);
+ case SIG_AD7820_DATA_REG:
+ adc_msb = data & 0xf0;
+ if(wr_rd_mode) {
+ if(event_sample < 0) {
+ start_sample(1.36);
}
- } else if(in_rate == out_rate) {
- in_mod = 0;
- out_mod = 0;
- out_count = 1;
- if(!(in_fifo->empty())) {
- adc_data = (uint8_t)(in_fifo->read() & 0xff);
- } else {
- adc_data = 0x00;
+ }
+ break;
+ case SIG_AD7820_CS:
+ f = ((data & mask) != 0) ? true : false;
+ if((f) && (cs_enabled != f)) {
+ req_convert = true;
+ if(event_sample >= 0) { // Discard before conversion.
+ cancel_event(this, event_sample);
+ event_sample = -1;
}
- write_signals(&output_data, adc_data);
- } else { // in_rate < out_rate
- int local_mod = out_rate % in_rate;
- int local_count = out_rate / in_rate;
- in_mod = 0;
- if(out_count == 0) {
- if(!(in_fifo->empty())) {
- adc_data = (uint8_t)(in_fifo->read() & 0xff);
- } else {
- adc_data = 0x00;
- }
- out_count = local_count;
+ } /*else if(!(f)) { // CONVERSION ABORT
+ if(event_sample >= 0) {
+ cancel_event(this, event_sample);
+ event_sample = -1;
}
- if(local_mod != 0) {
- out_mod = out_mod + local_mod;
- if(out_mod >= in_rate) {
- out_mod -= in_rate;
- out_count++;
- }
+ }*/
+ cs_enabled = f;
+ break;
+ case SIG_AD7820_WR_CONVERSION_MODE:
+ if((wr_rd_mode) && (cs_enabled)) {
+ // ToDo: Implement wr-rd-sampling sequence.
+ if(event_sample < 0) {
+ start_sample(1.36);
}
- write_signals(&output_data, adc_data);
- if(out_count > 0) out_count = out_count - 1;
- }
+ }
+ break;
+ case SIG_AD7820_SAMPLE_RATE:
+ this_sample_rate = data;
break;
}
}
-void AD7802KR::initialize_sampler(uint32_t irate, uint32_t orate)
-{
- in_rate = irate;
- out_rate = orate;
- if(in_rate > out_rate) {
- out_mod = 0;
- out_count = 1;
- in_mod = 0;
- } else if(in_rate == out_rate) {
- in_mod = 0;
- out_mod = 0;
- out_count = 1;
- } else { // in_rate < out_rate
- in_mod = 0;
- out_mod = 0;
- out_count = 0;
- }
- adc_data = 0x00;
- in_fifo->clear();
-}
-
-void AD7820KR::change_in_rate(int rate)
-{
- initialize_sampler(rate, out_rate);
-}
-
-void AD7820KR::change_out_rate(int rate)
-{
- initialize_sampler(in_rate, rate);
-}
-
-void AD7820KR::change_in_period(double usec)
-{
- int rate = (int)(1.0e6 / usec);
- initialize_sampler(rate, out_rate);
-}
-
-
-void AD7820KR::change_out_period(double usec)
-{
- int rate = (int)(1.0e6 / usec);
- initialize_sampler(in_rate, rate);
-}
-
-
#define STATE_VERSION 1
bool AD7820KR::process_state(FILEIO* state_fio, bool loading)
if(!state_fio->StateCheckInt32(this_device_id)) {
return false;
}
- if(!(in_fifo->process_state((void *)state_fio, loading))) {
- return false;
- }
state_fio->StateValue(adc_data);
- state_fio->StateValue(in_rate);
- state_fio->StateValue(out_rate);
- state_fio->StateValue(in_mod);
- state_fio->StateValue(out_count);
- state_fio->StateValue(out_mod);
+ state_fio->StateValue(adc_msb);
+ state_fio->StateValue(prev_clock);
+ state_fio->StateValue(wr_rd_mode);
+ state_fio->StateValue(req_convert);
+ state_fio->StateValue(this_sample_rate);
+ state_fio->StateValue(this_bank);
+ state_fio->StateValue(event_sample);
return true;
}
#include "../../common.h"
#include "../../fifo.h"
-#define SIG_AD7820_RESET 1
-#define SIG_AD7820_DO_SAMPLE 2 // SET A DATA (from any internal device)
-#define SIG_AD7820_PERIOD_OUT 3 // TICK A CLOCK
-#define SIG_AD7820_POP_FIFO 4
-#define SIG_AD7820_PEEK_FIFO 5
+#define SIG_AD7820_DATA_REG 1 // READ/SET A DATA
+#define SIG_AD7820_RESET 2 // REEST DEVICE (not implemented at real machine)
+#define SIG_AD7820_SET_SAMPLE_MODE 3 // NOT 0 = WR_RD_MODE, 0 = RD_MODE.
+#define SIG_AD7820_CS 4 // CS (Positive logic: differ from real hardware).
+#define SIG_AD7820_WR_CONVERSION_MODE 5 // Automatic conversion mode: MUST SET SAMPLE_MODE = WR_RD_MODE (not 0).
+#define SIG_AD7820_SAMPLE_RATE 6 // READ/SET SAMPLE RATE
// ToDo: Adjust sample rate.
class AD7820KR : public DEVICE {
// ADC
- outputs_t output_data;
- FIFO* in_fifo;
- uint32_t adc_data;
-
- int in_rate;
- int out_rate;
-
- int in_mod;
- int out_count;
- int out_mod;
+ // Note: AD7820KR controls/outputs *INT and *OFL as NEGATIVE logic, but this outputs POSITIVE logic 20190307 K.O
+ outputs_t outputs_intr;
+ outputs_t outputs_overflow;
+ outputs_t outputs_ready;
- void push_fifo(uint32_t data);
+ uint8_t adc_data;
+ uint8_t adc_msb;
+ uint32_t prev_clock;
+ bool req_convert;
+ bool wr_rd_mode;
+ int this_bank;
+ int this_sample_rate;
+ int event_sample;
+
+ void srart_sample(double usec);
public:
AD7820KR(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
{
- adc_fifo = new FIFO(96000 * 2); // DEPTH OK?
- initialize_output_signals(&output_data);
- set_device_name(_T("AD7820KR A/D CONVERTER"));
+ initialize_output_signals(&outputs_intr);
+ initialize_output_signals(&outputs_overflow);
+ initialize_output_signals(&outputs_ready);
+ this_sample_rate = 19200; // ToDo.
+ this_bank = 0; // ToDo.
+ wr_rd_mode = false;
+ req_convert = false;
+ adc_data = 0x00;
+ adc_msb = 0x00;
+ prev_clock = 0;
}
~AD7820KR()
{
- delete adc_fifo;
}
void initialize();
void release();
void reset();
+ void event_callback(int event_id, int err);
+
uint32_t read_signal(int ch);
-
- // Note: To sample:
- // 1. Set input rate (maybe host AUDIO_INPUT) and output rate (maybe emulated devices's rate).
- // 2. Get nSamples from HOST.
- // 3. Convert (adjust) sampled datas width to this device (maybe signed int or float -> unsigned 8bits).
- // 4. Push a data to this device's FIFO via write_signal(SIG_AD7820_DO_SAMPLE, converted_data) or set_data().
- // 5. Repeat 4. nSamples times.
- // 6. Go to 2.
- // Note2: To get sampled data (from emulated devices):
- // 1. Use set_context_output_data() to set target device(s).
- // 2. Transfer data within target's write_signal().
- // 3. Trigger to this device by AD7820KR::write_signal(SIG_AD7820_PERIOD_OUT,...).
- // See, vm/fmtowns/adpcm.[cpp|h] .
void write_signal(int ch, uint32_t data, uint32_t mask);
- void set_data(uint8_t data)
- {
- push_fifo(data);
- }
- void set_data(int8_t data)
- {
- uint8_t _n;
- if(data < 0) {
- _n = (uint8_t)(-data);
- _n = 128 - _n;
- } else {
- _n = (uint8_t)data;
- _n = _n + 128;
- }
- push_fifo(_n);
- }
- void set_data(int32_t data)
+ bool process_state(FILEIO* state_fio, bool loading);
+
+ // unique functions
+ void set_sample_rate(int val)
{
- uint8_t _n;
- data >>= 24;
- _n = (uint8_t)(data + 128);
- push_fifo(_n);
+ this_sample_rate = val;
}
- void set_data(uint32_t data)
+ void set_sound_bank(int val)
{
- uint8_t _n;
- data >>= 24;
- _n = (uint8_t)data;
- push_fifo(_n);
+ this_bank = val;
}
- void set_data(int16_t data)
+ void set_context_ready(DEVICE* device, int id, uint32_t mask)
{
- uint8_t _n;
- data >>= 8;
- _n = (uint8_t)(data + 128);
- push_fifo(_n);
+ register_output_signal(&output_ready, device, id, mask);
}
- void set_data(uint16_t data)
+ void set_context_interrupt(DEVICE* device, int id, uint32_t mask)
{
- uint8_t _n;
- data >>= 8;
- _n = (uint8_t)data;
- push_fifo(_n);
+ register_output_signal(&output_intr, device, id, mask);
}
- // Note: These functions are to set sample rate both in/out.
- void initialize_sampler(uint32_t irate, uint32_t orate);
- void change_in_rate(int rate);
- void change_in_period(double us);
- void change_out_rate(int rate);
- void change_out_period(double us);
-
- bool process_state(FILEIO* state_fio, bool loading);
-
- void set_context_output_data(DEVICE* device, int id, uint32_t mask)
+ void set_context_overflow(DEVICE* device, int id, uint32_t mask)
{
- register_output_signal(&output_data, device, id, mask);
+ register_output_signal(&output_overflow, device, id, mask);
}
-
};
#include "ad7820kr.h"
namespace FMTOWNS {
+
+#define EVENT_ADC_CLOCK 1
+#define EVENT_ADPCM_CLOCK 2
+
void ADPCM::initialize()
{
+ adc_fifo = new FIFO(64); // OK?
for(int i = 0; i < 8; i++) {
dac_int_mask[i] = true; // true = enable intrrupt.
dac_intr[i] = false;
}
intr_opx = false;
+ event_adc_clock = -1;
+ initialize_adc_clock(-1);
+ event_adpcm_clock = -1;
}
+void ADPCM::release()
+{
+ adc_fifo->release();
+ delete adc_fifo;
+}
+
void ADPCM::reset()
{
// Is clear FIFO?
+ adc_fifo->clear();
+ initialize_adc_clock(-1);
+ if(event_adpcm_clock >= 0) {
+ cancel_event(this, event_adpcm_clock);
+ }
+ register_event(this, EVENT_ADPCM_CLOCK, 16.0e6 / (384.0 * 2.0), true, &event_adpcm_clock); // Is this true?
+}
+
+void ADPCM::initialize_adc_clock(int freq)
+{
+ if(freq <= 0) {
+ freq = (int)d_adc->read_signal(SIG_AD7820_SAMPLE_RATE);
+ }
+ if(event_adc_clock >= 0) {
+ cancel_event(this, event_adc_clock);
+ }
+ d_adc->write_signal(SIG_AD7820_DATA_REG, 0x00, 0x00);
+ d_adc->write_signal(SIG_AD7820_CS, 0xffffffff, 0xffffffff);
+ d_adc->write_signal(SIG_AD7820_WR_CONVERSION_MODE, 0, 0xffffffff); // READ MODE..
+ register_event(this, EVENT_ADC_CLOCK, 1.0e6 / (double)freq, true, &event_adc_clock);
+}
+
+void ADPCM::event_callback(int id, int err)
+{
+ switch(id) {
+ case EVENT_ADC_CLOCK:
+ d_adc->write_signal(SIG_AD7820_WR_CONVERSION_MODE, 0, 0xffffffff); // READ MODE
+ d_adc->write_signal(SIG_AD7820_CS, 0xffffffff, 0xffffffff);
+ d_adc->read_data8(SIG_AD7820_DATA_REG); // Dummy read, start to sample.
+ break;
+ case EVENT_ADPCM_CLOCK:
+ d_rf5c68->write_signal(SIG_RF5C68_DAC_PERIOD, 1, 1);
+ break;
+ }
}
+
uint32_t ADPCM::read_io8(uint32_t addr)
{
/*
} else if(ch == SIG_ADPCM_OPX_INTR) { // SET/RESET INT13
intr_opx = ((data & mask) != 0);
write_signals(&output_intr, (intr_opx) ? 0xffffffff : 0x00000000);
- } else if(ch == SIG_ADPCM_PUSH_FIFO) { // Push data to FIFO from ADC.
- if(adc_fifo->full()) {
- adc_fifo->read(); // Dummy read
+ } else if(ch == SIG_ADPCM_ADC_INTR) { // Push data to FIFO from ADC.
+ if((data & mask) != 0) {
+ uint32_t n_data = d_adc->read_signal(SIG_AD7820_DATA_REG);
+ d_adc->write_signal(SIG_AD7820_CS, 0, 0xffffffff);
+ if(!(adc_fifo->full())) {
+ adc_fifo->write((int)(n_data & 0xff));
+ }
}
- adc_fifo->write((int)(data & 0xff));
}
}
fontrom_20pix = new FONT_ROM_20PIX(this, emu);
#endif
serialrom = new SERIAL_ROM(this, emu);
-
+ adpcm = new ADPCM(this, emu);
+ mixer = new MIXER(this, emu); // Pseudo mixer.
+
+
adc = new AD7820KR(this, emu);
- adpcm = new RF5C68(this, emu);
+ rf5c68 = new RF5C68(this, emu);
e_volume[0] = new MB87878(this, emu);
e_volume[1] = new MB87878(this, emu);
#endif
set_machine_type(machine_id, cpu_id);
-
// set contexts
event->set_context_cpu(cpu, cpu_clock);
- event->set_context_sound(beep);
- event->set_context_sound(opn2);
- event->set_context_sound(adpcm);
- event->set_context_sound(cdc);
- //event->set_context_sound_in(cdc);
- //event->set_context_sound_in(line_in);
- //event->set_context_sound_in(mic);
- //event->set_context_sound_in(modem);
+ adc_in_ch = -1;
+ line_in_ch = -1;
+ modem_in_ch = -1;
+ mic_in_ch = -1;
+
+ // Use pseudo mixer instead of event.Due to using ADC.
+ line_mix_ch = -1;
+ modem_mix_ch = -1;
+ mic_mix_ch = -1;
+ //line_mix_ch = mixer->set_context_sound(line_in);
+ //modem_mix_ch = mixer->set_context_sound(modem_in);
+ //mic_mix_ch = mixer->set_context_sound(mic_in);
+ beep_mix_ch = mixer->set_context_sound(beep);
+ pcm_mix_ch = mixer->set_context_sound(rf5c68);
+ opn2_mix_ch = mixer->set_context_sound(opn2);
+ cdc_mix_ch = mixer->set_context_sound(cdc);
+ mixer->set_interpolate_filter_freq(pcm_mix_ch, 4000); // channel, freq; disable if freq <= 0.
+
+ event->set_context_sound(mixer);
+
if(fdc->load_sound_data(MB8877_SND_TYPE_SEEK, _T("FDDSEEK.WAV"))) {
event->set_context_sound(fdc);
}
cdc->set_context_pic(pic, SIG_I8259_CHIP1 | SIG_I8259_IR1);
crtc->set_context_vsync(pic, SIG_I8259_CHIP1 | SIG_I8259_IR3); // VSYNC
- sound->set_context_pic(pic, SIG_I8259_CHIP1 | SIG_I8259_IR5); // ADPCM AND OPN2
- sound->set_context_opn2(opn2);
- sound->set_context_adpcm(adpcm);
- sound->set_context_adc(adc);
+ adpcm->set_context_pic(pic, SIG_I8259_CHIP1 | SIG_I8259_IR5); // ADPCM AND OPN2
+ adpcm->set_context_opn2(opn2);
+ adpcm->set_context_adpcm(rf5c68);
+ adpcm->set_context_adc(adc);
+ rf5c68->set_context_interrupt_boundary(adpcm, SIG_ADPCM_WRITE_INTERRUPT, 0xffffffff);
+ opn2->set_context_interrupt(adpcm, SIG_ADPCM_OPX_INTR, 0xffffffff);
-
+ adc->set_sample_rate(19200);
+ adc->set_sound_bank(-1);
+ adc->set_context_interrupt(adpcm, SIG_ADPCM_ADC_INTR, 0xffffffff);
scsi->set_context_dma(dma);
scsi->set_context_pic(pic);
#ifdef USE_DEBUGGER
cpu->set_context_debugger(new DEBUGGER(this, emu));
#endif
-
// i/o bus
io->set_iomap_alias_rw(0x00, pic, I8259_ADDR_CHIP0 | 0);
void VM::initialize_sound(int rate, int samples)
{
+ emu->lock_vm();
// init sound manager
event->initialize_sound(rate, samples);
// init sound gen
beep->initialize_sound(rate, 8000);
+
+ // add_sound_in_source() must add after per initialize_sound().
+ adc_in_ch = event->add_sound_in_source(rate, samples, 2);
+ mixer->set_context_out_line(adc_in_ch);
+ adc->set_sample_rate(19200);
+ adc->set_sound_bank(adc_in_ch);
+ mixer->set_context_sample_out(adc_in_ch, rate, samples); // Must be 2ch.
+
+ // ToDo: Check recording sample rate & channels.
+ mic_in_ch = event->add_sound_in_source(rate, samples, 2);
+ mixer->set_context_mic_in(mic_in_ch, rate, samples);
+
+ line_in_ch = event->add_sound_in_source(rate, samples, 2);
+ mixer->set_context_line_in(line_in_ch, rate, samples);
+ emu->unlock_vm();
}
uint16_t* VM::create_sound(int* extra_frames)
return event->get_sound_buffer_ptr();
}
-// ToDo: Sound IN as double buffer.
-bool VM::clear_sound_in()
+void VM::clear_sound_in()
{
- bool f = false;
- sound_in_buf_bank = !sound_in_buf_bank;
- lock_soundbuf();
-
- sound_in_buf = sound_in_buf_pool[(sound_in_buf_bank) ? 1 : 0];
- if(sound_in_buf != NULL) {
- memset(sound_in_buf, 0x00, sound_in_bufsize * 2 * sizeof(int32_t));
- f = true;
- } else {
- f = false;
- }
- for(int ch = 0; ch < 4; ch++) {
- sound_in_bufptr[ch] = 0;
- }
- sound_in_outptr = 0;
- unlock_soundbuf();
- return f;
-}
-
-void VM::initialize_sample_in_buf(int samples)
-{
- sound_in_bufsize = 0;
- sound_in_buf = NULL;
- if(samples <= 0) return;
-
- sound_in_bufsize = samples;
- sound_in_buf_pool = (int32_t*)malloc(samples * sizeof(int32_t) * 2);
-
+ event->clear_sound_in_source(adc_in_ch);
+ event->clear_sound_in_source(mic_in_ch);
+ event->clear_sound_in_source(line_in_ch);
+ return;
}
-int VM::get_samples_in_buf(int ch, int32* dst, int samples)
+int VM::get_sound_in_data(int ch, int32_t* dst, int expect_samples, int expect_rate, int expect_channels)
{
- bool over = false;
+ if(dst == NULL) return 0;
if(samples <= 0) return 0;
- if(samples >= sound_in_bufsize) return 0;
- if((sound_in_outptr + samples) >= sound_in_bufsize) {
- samples = sound_in_bufsize - sound_in_outptr;
- over = true;
- }
- lock_soundbuf();
- memcpy(dst, &(sound_in_buf[sound_in_outptr << 1]), samples * sizeof(int32_t) * 2);
- unlock_soundbuf();
-
+ int n_ch = -1;
+ switch(ch) {
+ case 0x00:
+ n_ch = line_in_ch;
+ break;
+ case 0x01:
+ n_ch = mic_in_ch;
+ break;
+ case 0x100:
+ n_ch = adc_in_ch;
+ break;
+ }
+ if(n_ch < 0) return 0;
+ samples = event->get_sound_in_data(n_ch, dst, expect_samples, expect_rate, expect_channels);
return samples;
}
-int VM::get_samples_length_sound_in()
-{
- return sound_in_bufsize;
-}
-
-int VM::sound_in(int ch, int32* src, int samples)
+// Write to event's buffer
+int VM::sound_in(int ch, int32_t* src, int samples)
{
if(ch < 0) return 0;
- if(ch >= 4) return 0;
- int left = samples;
- int np = sound_in_bufptr[ch];
- int sp = 0;
- for(;left > 0; left--) {
- if(np >= (sound_in_bufsize << 1)) break;
- lock_soundbuf();
- sound_in_buf[np + 0] = sound_in_buf[np + 0] + src[sp + 0];
- sound_in_buf[np + 1] = sound_in_buf[np + 1] + src[sp + 1];
- if(sound_in_buf[np + 0] > 32767) sound_in_buf[np + 0] = 32767;
- if(sound_in_buf[np + 0] < -32768) sound_in_buf[np + 0] = -32768;
- if(sound_in_buf[np + 1] > 32767) sound_in_buf[np + 1] = 32767;
- if(sound_in_buf[np + 1] < -32768) sound_in_buf[np + 1] = -32768;
- unlock_soundbuf();
- np = np + 2;
- sp = sp + 2;
- }
- return left;
+ if(ch >= 2) return 0;
+ int n_ch = -1;
+ switch(ch) {
+ case 0x100: // ADC in from MIXER, not connected.
+ break;
+ case 0x00: // LINE
+ n_ch = line_in_ch;
+ break;
+ case 0x01: // MIC
+ n_ch = mic_in_ch;
+ break;
+ }
+ if(n_ch < 0) return 0;
+
+ int ss = 0;
+ {
+ emu->lock_vm();
+ ss = event->write_sound_in_buffer(n_ch, src, samples);
+ emu->unlock_vm();
+
+ }
+ return ss;
}
#ifdef USE_SOUND_VOLUME
if(ch >= 7) ch++;
#endif
if(ch == 0) { // BEEP
- beep->set_volume(0, decibel_l, decibel_r);
+ mixer->set_volume(beep_mix_ch, decibel_l, decibel_r);
}
else if(ch == 1) { // CD-ROM
- e_volume[1]->set_volume(0, decibel_l);
- e_volume[1]->set_volume(1, decibel_r);
+ //e_volume[1]->set_volume(0, decibel_l);
+ //e_volume[1]->set_volume(1, decibel_r);
+ mixer->set_volume(cdc_mix_ch, decibel_l, decibel_r);
}
else if(ch == 2) { // OPN2
- opn2->set_volume(0, decibel_l, decibel_r);
+ mixer->set_volume(opn2_mix_ch, decibel_l, decibel_r);
}
else if(ch == 3) { // ADPCM
- adpcm->set_volume(0, decibel_l, decibel_r);
+ mixer->set_volume(pcm_mix_ch, decibel_l, decibel_r);
}
else if(ch == 4) { // LINE IN
- e_volume[0]->set_volume(0, decibel_l);
- e_volume[0]->set_volume(1, decibel_r);
+ //mixer->set_volume(line_mix_ch, decibel_l, decibel_r);
}
else if(ch == 5) { // MIC
- e_volume[1]->set_volume(2, (decibel_l + decibel_r) / 2);
+ //mic->set_volume(0, (decibel_l + decibel_r) / 2);
}
else if(ch == 6) { // MODEM
- e_volume[1]->set_volume(2, (decibel_l + decibel_r) / 2);
+ //modem->set_volume(0, (decibel_l + decibel_r) / 2);
}
+#ifdef HAS_2ND_ADPCM
else if(ch == 7) { // ADPCM
adpcm2->set_volume(0, decibel_l, decibel_r);
}
+#endif
else if(ch == 8) { // FDD
fdc->set_volume(0, decibel_l, decibel_r);
}
#define STATE_VERSION 3
-void VM::save_state(FILEIO* state_fio)
-{
- state_fio->FputUint32(STATE_VERSION);
-
- for(DEVICE* device = first_device; device; device = device->next_device) {
- device->save_state(state_fio);
- }
-}
-
-bool VM::load_state(FILEIO* state_fio)
+bool VM::process_state(FILEIO* state_fio, bool loading)
{
- if(state_fio->FgetUint32() != STATE_VERSION) {
- return false;
- }
- for(DEVICE* device = first_device; device; device = device->next_device) {
- if(!device->load_state(state_fio)) {
+ if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+ return false;
+ }
+ for(DEVICE* device = first_device; device; device = device->next_device) {
+ // Note: typeid(foo).name is fixed by recent ABI.Not decr. 6.
+ // const char *name = typeid(*device).name();
+ // But, using get_device_name() instead of typeid(foo).name() 20181008 K.O
+ const char *name = device->get_device_name();
+ int len = strlen(name);
+ if(!state_fio->StateCheckInt32(len)) {
return false;
}
- }
+ if(!state_fio->StateCheckBuffer(name, len, 1)) {
+ return false;
+ }
+ if(!device->process_state(state_fio, loading)) {
+ if(loading) {
+ printf("Data loading Error: DEVID=%d\n", device->this_device_id);
+ }
+ return false;
+ }
+ }
+ // Machine specified.
+ state_fio->StateValue(line_mix_ch);
+ state_fio->StateValue(modem_mix_ch);
+ state_fio->StateValue(mic_mix_ch);
+ state_fio->StateValue(beep_mix_ch);
+ state_fio->StateValue(pcm_mix_ch);
+ state_fio->StateValue(opn2_mix_ch);
+ state_fio->StateValue(cdc_mix_ch);
return true;
}