void adlib_io_write_base(ioport_t port, Bit8u value) { adlib_time_last = GETusTIME(0); #ifdef HAS_YMF262 YMF262Write(opl3, port, value); #endif }
void adlib_timer(void) { #ifdef HAS_YMF262 int i, nsamps; double period; long long now = GETusTIME(0); if (adlib_time_cur - adlib_time_last > ADLIB_THRESHOLD) { ADLIB_STOP(); pcm_flush(adlib_strm); } if (ADLIB_RUNNING()) { period = pcm_samp_period(opl3_rate, 2); nsamps = (now - adlib_time_cur) / period; if (nsamps > OPL3_MAX_BUF) nsamps = OPL3_MAX_BUF; nsamps -= nsamps % 2; if (nsamps) { adlib_process_samples(nsamps / 2); adlib_time_cur += nsamps * period; S_printf("SB: processed %i Adlib samples\n", nsamps); } } for (i = 0; i < 2; i++) { if (opl3_timers[i] > 0 && now > opl3_timers[i]) { S_printf("Adlib: timer %i expired\n", i); opl3_timers[i] = 0; YMF262TimerOver(opl3, i); } } #endif }
void rtc_run(void) { static hitimer_t last_time = -1; int rate; hitimer_t ticks_m, cur_time = GETusTIME(0); if (last_time == -1 || last_time > cur_time) { last_time = cur_time; return; } rate = rtc_get_rate(GET_CMOS(CMOS_STATUSA) & 0x0f); ticks_m = (cur_time - last_time) * rate; q_ticks_m += ticks_m; last_time = cur_time; if (debug_level('h') > 8) h_printf("RTC: A=%hhx B=%hhx C=%hhx rate=%i queued=%lli added=%lli\n", GET_CMOS(CMOS_STATUSA), GET_CMOS(CMOS_STATUSB), GET_CMOS(CMOS_STATUSC), rate, (long long)q_ticks_m, (long long)ticks_m); if (q_ticks_m >= 1000000) { Bit8u old_c = GET_CMOS(CMOS_STATUSC); SET_CMOS(CMOS_STATUSC, old_c | 0x40); if ((GET_CMOS(CMOS_STATUSB) & 0x40) && !(GET_CMOS(CMOS_STATUSC) & 0x80)) { SET_CMOS(CMOS_STATUSC, GET_CMOS(CMOS_STATUSC) | 0x80); if (debug_level('h') > 7) h_printf("RTC: periodic IRQ, queued=%lli, added=%lli\n", (long long)q_ticks_m, (long long)ticks_m); pic_request(PIC_IRQ8); } if (!(old_c & 0x40)) q_ticks_m -= 1000000; } }
static void opl3_set_timer(void *param, int num, double interval_Sec) { long long *timers = param; timers[num] = interval_Sec > 0 ? GETusTIME(0) + interval_Sec * 1000000 : 0; S_printf("Adlib: timer %i set to %ius\n", num, (int) (interval_Sec * 1000000)); }
static void midoflus_start(void) { S_printf("MIDI: starting fluidsynth\n"); mf_time_base = GETusTIME(0); pthread_mutex_lock(&syn_mtx); pcm_prepare_stream(pcm_stream); fluid_sequencer_process(sequencer, 0); output_running = 1; pthread_mutex_unlock(&syn_mtx); }
static void nullsnd_timer(void) { double time, frag_time; if (!running || locked) return; frag_time = pcm_frag_period(frag_size, ¶ms); time = GETusTIME(0); while (time - last_time > frag_time) { last_time += frag_time; calls.get_data(NULL, frag_size, ¶ms); } }
static void midoflus_write(unsigned char val) { int ret; unsigned long long now = GETusTIME(0); int msec = (now - mf_time_base) / 1000; if (!output_running) midoflus_start(); fluid_sequencer_process(sequencer, msec); ret = fluid_sequencer_add_midi_data_to_buffer(synthSeqID, &val, 1); if (ret != FLUID_OK) S_printf("MIDI: failed sending midi event\n"); }
static void *synth_thread(void *arg) { while (1) { sem_wait(&syn_sem); pthread_mutex_lock(&syn_mtx); if (!output_running) { pthread_mutex_unlock(&syn_mtx); continue; } pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); process_samples(GETusTIME(0), FLUS_MIN_BUF); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_mutex_unlock(&syn_mtx); } return NULL; }
static void dspio_start_input(struct dspio_state *state) { if (state->input_running) return; S_printf("SB: starting input\n"); state->input_time_cur = GETusTIME(0); state->input_running = 1; if (!state->dma.rate) { S_printf("SB: not starting recorder\n"); return; } if (!state->pcm_input_running) { pcm_reset_player(state->i_handle); state->pcm_input_running = 1; } }
//Read the current timer state, will use current double static Bit8u AdlibChip__Read(AdlibTimer *timer) { long long time = GETusTIME(0); AdlibTimer__Update(&timer[0], time); AdlibTimer__Update(&timer[1], time); Bit8u ret = 0; //Overflow won't be set if a channel is masked if ( timer[0].overflow ) { ret |= 0x40; ret |= 0x80; } if ( timer[1].overflow ) { ret |= 0x20; ret |= 0x80; } return ret; }
static int dspio_run_dma(struct dspio_state *state) { #define DMA_TIMEOUT_US 100000 int ret; struct dspio_dma *dma = &state->dma; hitimer_t now = GETusTIME(0); sb_dma_processing(); // notify that DMA busy ret = do_run_dma(state); if (ret) { sb_handle_dma(); dma->time_cur = now; } else if (now - dma->time_cur > DMA_TIMEOUT_US) { S_printf("SB: Warning: DMA busy for too long, releasing\n"); // error("SB: DMA timeout\n"); sb_handle_dma_timeout(); } return ret; }
void dspio_start_dma(void *dspio) { int dma_cnt = 0; DSPIO->dma.running = 1; DSPIO->dma.time_cur = GETusTIME(0); get_dma_params(&DSPIO->dma); if (DSPIO->dma.input) { dspio_start_input(DSPIO); } else { dma_cnt = dspio_fill_output(DSPIO); if (DSPIO->dma.running && dspio_output_fifo_filled(DSPIO)) S_printf("SB: Output filled, processed %i DMA cycles\n", dma_cnt); else S_printf("SB: Output fillup incomplete (%i %i %i)\n", DSPIO->dma.running, DSPIO->output_running, dma_cnt); } }
static void midoflus_stop(void *arg) { long long now; int msec; if (!output_running) return; now = GETusTIME(0); msec = (now - mf_time_base) / 1000; S_printf("MIDI: stopping fluidsynth at msec=%i\n", msec); pthread_mutex_lock(&syn_mtx); /* advance past last event */ fluid_sequencer_process(sequencer, msec); /* shut down all active notes */ fluid_synth_system_reset(synth); if (pcm_running) pcm_flush(pcm_stream); pcm_running = 0; output_running = 0; pthread_mutex_unlock(&syn_mtx); }
//Check for it being a write to the timer static bool AdlibChip__WriteTimer(AdlibTimer *timer, Bit32u reg, Bit8u val) { switch ( reg ) { case 0x02: timer[0].counter = val; return true; case 0x03: timer[1].counter = val; return true; case 0x04: { long long time = GETusTIME(0); if ( val & 0x80 ) { AdlibTimer__Reset(&timer[0], time); AdlibTimer__Reset(&timer[1], time); } else { AdlibTimer__Update(&timer[0], time); AdlibTimer__Update(&timer[1], time); if ( val & 0x1 ) { AdlibTimer__Start(&timer[0], time, 80); S_printf("Adlib: timer 0 set to %lluus\n", timer[0].delay); } else { AdlibTimer__Stop(&timer[0]); } timer[0].masked = (val & 0x40) > 0; if ( timer[0].masked ) timer[0].overflow = false; if ( val & 0x2 ) { AdlibTimer__Start(&timer[1], time, 320); S_printf("Adlib: timer 1 set to %lluus\n", timer[1].delay); } else { AdlibTimer__Stop(&timer[1]); } timer[1].masked = (val & 0x20) > 0; if ( timer[1].masked ) timer[1].overflow = false; } return true; } } return false; }
static void dspio_process_dma(struct dspio_state *state) { int dma_cnt, nfr, in_fifo_cnt, out_fifo_cnt, i, j, tlocked; unsigned long long time_dst; double output_time_cur; sndbuf_t buf[PCM_MAX_BUF][SNDBUF_CHANS]; static int warned; dma_cnt = in_fifo_cnt = out_fifo_cnt = 0; if (state->dma.running) { state->dma.stereo = sb_dma_samp_stereo(); state->dma.rate = sb_get_dma_sampling_rate(); state->dma.samp_signed = sb_dma_samp_signed(); state->dma.dsp_fifo_enabled = sb_fifo_enabled(); dma_cnt += state->dma.input ? dspio_drain_input(state) : dspio_fill_output(state); } if (!state->output_running && !state->input_running) return; time_dst = GETusTIME(0); if (state->output_running) { output_time_cur = pcm_time_lock(state->dma_strm); tlocked = 1; nfr = calc_nframes(state, output_time_cur, time_dst); } else { nfr = 0; tlocked = 0; } for (i = 0; i < nfr; i++) { for (j = 0; j < state->dma.stereo + 1; j++) { if (state->dma.running && !dspio_output_fifo_filled(state)) { if (!dspio_run_dma(state)) break; dma_cnt++; } if (!dspio_get_output_sample(state, &buf[i][j], state->dma.is16bit)) break; #if 0 /* if speaker disabled, overwrite DMA data with silence */ /* on SB16 is not used */ if (!state->speaker) dma_get_silence(state->dma.samp_signed, state->dma.is16bit, &buf[i][j]); #endif } if (j != state->dma.stereo + 1) break; out_fifo_cnt++; } if (out_fifo_cnt && state->dma.rate) { pcm_write_interleaved(buf, out_fifo_cnt, state->dma.rate, pcm_get_format(state->dma.is16bit, state->dma.samp_signed), state->dma.stereo + 1, state->dma_strm); output_time_cur = pcm_get_stream_time(state->dma_strm); if (state->dma.running && output_time_cur > time_dst - 1) { pcm_clear_flag(state->dma_strm, PCM_FLAG_POST); warned = 0; } } if (out_fifo_cnt < nfr) { /* not enough samples, see why */ if (!sb_dma_active()) { dspio_stop_output(state); } else { if (nfr && !warned) { S_printf("SB: Output FIFO exhausted while DMA is still active (ol=%f)\n", time_dst - output_time_cur); warned = 1; } if (state->dma.running) S_printf("SB: Output FIFO exhausted while DMA is running (no DACK?)\n"); /* DMA is active but currently not running and the FIFO is * already exhausted. Normally we should flush the channel * and stop the output timing. * HACK: try to not flush the channel for as long as possible * in a hope the PCM buffers are large enough to hold till * the DMA is restarted. */ pcm_set_flag(state->dma_strm, PCM_FLAG_POST); /* awake dosemu */ reset_idle(0); } } if (tlocked) pcm_time_unlock(state->dma_strm); /* TODO: sync also input time with PCM? */ if (state->input_running) nfr = calc_nframes(state, state->input_time_cur, time_dst); else nfr = 0; if (nfr && state->i_started && sb_input_enabled()) { struct player_params params; params.rate = state->dma.rate; params.channels = state->dma.stereo + 1; params.format = pcm_get_format(state->dma.is16bit, state->dma.samp_signed); params.handle = state->i_handle; nfr = pcm_data_get_interleaved(buf, nfr, ¶ms); } if (!state->i_started) { for (i = 0; i < nfr; i++) { for (j = 0; j < state->dma.stereo + 1; j++) dma_get_silence(state->dma.samp_signed, state->dma.is16bit, &buf[i][j]); } } for (i = 0; i < nfr; i++) { for (j = 0; j < state->dma.stereo + 1; j++) { if (sb_input_enabled()) { if (!dspio_put_input_sample(state, &buf[i][j], state->dma.is16bit)) break; } } if (j == state->dma.stereo + 1) in_fifo_cnt++; for (j = 0; j < state->dma.stereo + 1; j++) { if (state->dma.running) { if (!dspio_run_dma(state)) break; dma_cnt++; } } if (!state->input_running || (j != state->dma.stereo + 1)) break; } if (in_fifo_cnt) { if (state->dma.rate) { state->input_time_cur += in_fifo_cnt * pcm_frame_period_us(state->dma.rate); } else { state->input_time_cur = time_dst; } } if (debug_level('S') >= 7 && (in_fifo_cnt || out_fifo_cnt || dma_cnt)) S_printf("SB: Processed %i %i FIFO, %i DMA, or=%i dr=%i\n", in_fifo_cnt, out_fifo_cnt, dma_cnt, state->output_running, state->dma.running); }
static void nullsnd_start(void) { last_time = GETusTIME(0); running = 1; }
void dspio_stop_midi(void *dspio) { DSPIO->midi_time_cur = GETusTIME(0); midi_stop(); }
Bit32u dspio_get_midi_in_time(void *dspio) { Bit32u delta = GETusTIME(0) - DSPIO->midi_time_cur; S_printf("SB: midi clock, delta=%i\n", delta); return delta; }