static void midotmdty_done(void) { const char *cmd1 = "CLOSE\n"; const char *cmd2 = "QUIT\n"; char buf[255]; int n, status; if (TMDTY_CAPT) remove_from_io_select(data_sock, 1); write(ctrl_sock_out, cmd1, strlen(cmd1)); n = read(ctrl_sock_in, buf, sizeof(buf) - 1); buf[n] = 0; S_printf("\tClose: %s\n", buf); if (!strstr(buf, "already closed")) { shutdown(data_sock, 2); close(data_sock); } write(ctrl_sock_out, cmd2, strlen(cmd2)); n = read(ctrl_sock_in, buf, sizeof(buf) - 1); buf[n] = 0; S_printf("\tQuit: %s\n", buf); close(ctrl_sock_out); if (tmdty_pid != -1) { waitpid(tmdty_pid, &status, 0); tmdty_pid = -1; } }
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 }
static int midotmdty_init(void) { const char *cmd1 = "OPEN %s\n"; char buf[255]; char *pbuf; int n, i, data_port; if (!midotmdty_detect()) return FALSE; i = 1; if (*(char *) &i == 1) sprintf(buf, cmd1, "lsb"); else sprintf(buf, cmd1, "msb"); S_printf("\t%s", buf); write(ctrl_sock_out, buf, strlen(buf)); n = read(ctrl_sock_in, buf, sizeof(buf) - 1); buf[n] = 0; S_printf("\tOpen: %s\n", buf); pbuf = strstr(buf, " is ready"); if (!pbuf) return FALSE; *pbuf = 0; pbuf = strrchr(buf, ' '); if (!pbuf) return FALSE; data_port = atoi(pbuf + 1); if (!data_port) { error("Can't determine the data port number!\n"); close(data_sock); close(ctrl_sock_out); return FALSE; } S_printf("\tUsing port %d for data\n", data_port); i = 1; setsockopt(data_sock, SOL_TCP, TCP_NODELAY, &i, sizeof(i)); data_adr.sin_port = htons(data_port); if (connect(data_sock, (struct sockaddr *) &data_adr, sizeof(data_adr)) != 0) { error("Can't open data connection!\n"); close(data_sock); close(ctrl_sock_out); return FALSE; } n = read(ctrl_sock_in, buf, sizeof(buf) - 1); buf[n] = 0; S_printf("\tConnect: %s\n", buf); if (TMDTY_CAPT) { add_to_io_select(data_sock, 1, midotmdty_io); pcm_stream = pcm_allocate_stream(2, "MIDI"); } return TRUE; }
static void dspio_stop_input(struct dspio_state *state) { if (!state->input_running) return; S_printf("SB: stopping input\n"); state->input_running = 0; if (!state->dma.rate) { S_printf("SB: not stopping recorder\n"); return; } if (!sb_dma_active()) state->pcm_input_running = 0; }
static int sdlsnd_open(void *arg) { SDL_AudioSpec spec, spec1; int err; S_printf("Initializing SDL sound output\n"); err = SDL_InitSubSystem(SDL_INIT_AUDIO); if (err) { error("SDL audio init failed, %s\n", SDL_GetError()); return 0; } spec.freq = 44100; spec.format = AUDIO_S16LSB; spec.channels = 2; spec.samples = 1024; spec.callback = sdlsnd_callback; spec.userdata = NULL; dev = SDL_OpenAudioDevice(NULL, 0, &spec, &spec1, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (!dev) { SDL_QuitSubSystem(SDL_INIT_AUDIO); error("SDL sound init failed: %s\n", SDL_GetError()); return 0; } params.rate = spec1.freq; params.format = PCM_FORMAT_S16_LE; params.channels = spec1.channels; pcm_setup_hpf(¶ms); return 1; }
void opl3_init(void) { emu_iodev_t io_device; S_printf("SB: OPL3 Initialization\n"); /* This is the FM (Adlib + Advanced Adlib) */ io_device.read_portb = adlib_io_read; io_device.write_portb = adlib_io_write; io_device.read_portw = NULL; io_device.write_portw = NULL; io_device.read_portd = NULL; io_device.write_portd = NULL; io_device.handler_name = "Adlib (+ Advanced) Emulation"; io_device.start_addr = ADLIB_BASE; io_device.end_addr = ADLIB_BASE + 3; io_device.irq = EMU_NO_IRQ; io_device.fd = -1; if (port_register_handler(io_device, 0) != 0) { error("ADLIB: Cannot registering port handler\n"); } #ifdef HAS_YMF262 opl3 = YMF262Init(OPL3_INTERNAL_FREQ, opl3_rate); YMF262SetTimerHandler(opl3, opl3_set_timer, &opl3_timers); YMF262SetUpdateHandler(opl3, opl3_update, NULL); #endif }
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; } }
static int midotmdty_check_ready(char *buf, int size, int verb) { fd_set rfds; struct timeval tv; int selret, n; FD_ZERO(&rfds); FD_SET(ctrl_sock_in, &rfds); tv.tv_sec = 3; tv.tv_usec = 0; while ((selret = select(ctrl_sock_in + 1, &rfds, NULL, NULL, &tv)) > 0) { n = read(ctrl_sock_in, buf, size - 1); buf[n] = 0; if (!n) break; if (verb) S_printf("\tInit: %s", buf); if (strstr(buf, "220 TiMidity++")) return TRUE; FD_ZERO(&rfds); FD_SET(ctrl_sock_in, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; } if (selret < 0) perror("select()"); return FALSE; }
static void midotmdty_reset(void) { const char *cmd1 = "RESET\n"; const char *cmd2 = "PROTOCOL midi\n"; char buf[255]; int n; write(ctrl_sock_out, cmd1, strlen(cmd1)); n = read(ctrl_sock_in, buf, sizeof(buf) - 1); buf[n] = 0; S_printf("\tReset: %s\n", buf); write(ctrl_sock_out, cmd2, strlen(cmd2)); n = read(ctrl_sock_in, buf, sizeof(buf) - 1); buf[n] = 0; S_printf("\tSetup: %s\n", buf); }
static void dspio_start_output(struct dspio_state *state) { if (state->output_running) return; S_printf("SB: starting output\n"); pcm_prepare_stream(state->dma_strm); state->output_running = 1; }
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 dspio_stop_output(struct dspio_state *state) { if (!state->output_running) return; S_printf("SB: stopping output\n"); pcm_flush(state->dma_strm); state->output_running = 0; }
static int sndsdl_cfg(void *arg) { char *p; int l; if (config.sdl_sound == 1) return PCM_CF_ENABLED; l = strlen(sdlsnd_name); p = strstr(config.sound_driver, sdlsnd_name); if (p && (p == config.sound_driver || p[-1] == ',') && (p[l] == 0 || p[l] == ',')) { S_printf("PCM: Enabling sdl driver\n"); return PCM_CF_ENABLED; } else if (strlen(config.sound_driver)) { S_printf("PCM: Disabling sdl driver\n"); return PCM_CF_DISABLED; } return 0; }
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_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 int midooss_init(void *arg) { char *name = "/dev/sequencer"; seq_fd = RPT_SYSCALL(open(name, O_WRONLY)); if (seq_fd == -1) { S_printf("%s: unable to open %s for writing: %s\n", midooss_name, name, strerror(errno)); return 0; } return 1; }
//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 int midipipe_init(void *arg) { char *name = DOSEMU_MIDI_IN_PATH; pipe_fd = RPT_SYSCALL(open(name, O_RDONLY | O_NONBLOCK)); if (pipe_fd == -1) { S_printf("%s: unable to open %s for reading: %s\n", midipipe_name, name, strerror(errno)); return 0; } add_to_io_select(pipe_fd, midipipe_io, NULL); return 1; }
static int midoalsa_init(void *arg) { int err; err = snd_rawmidi_open(NULL, &handle, device, SND_RAWMIDI_NONBLOCK | SND_RAWMIDI_SYNC); if (err) { S_printf("%s: unable to open %s for writing: %s\n", midoalsa_name, device, snd_strerror(err)); return 0; } return 1; }
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"); }
int dspio_input_disable(void *dspio, enum MixChan mc) { struct dspio_state *state = dspio; switch (mc) { case MC_LINE: if (!state->lin_input_running) return 0; pcm_stop_input((void *)MC_LINE); state->lin_input_running = 0; S_printf("SB: disabled LINE\n"); break; case MC_MIC: if (!state->mic_input_running) return 0; pcm_stop_input((void *)MC_MIC); state->mic_input_running = 0; S_printf("SB: disabled MIC\n"); break; default: return 0; } return 1; }
static int midoalsa_open(snd_rawmidi_t **handle_p, const char *dev_name) { int err; err = snd_rawmidi_open(NULL, handle_p, dev_name, SND_RAWMIDI_NONBLOCK | SND_RAWMIDI_SYNC); if (err) { S_printf("%s: unable to open %s for writing: %s\n", midoalsa_name, dev_name, snd_strerror(err)); return 0; } /* NONBLOCK flag is needed only so that open() not to block forever */ snd_rawmidi_nonblock(*handle_p, 0); return 1; }
static int do_run_dma(struct dspio_state *state) { Bit8u dma_buf[2]; struct dspio_dma *dma = &state->dma; dma_get_silence(dma->samp_signed, dma->is16bit, dma_buf); if (!dma->silence) { if (dma->input) dspio_get_dma_data(state, dma_buf, dma->is16bit); if (dma_pulse_DRQ(dma->num, dma_buf) != DMA_DACK) { S_printf("SB: DMA %i doesn't DACK!\n", dma->num); return 0; } if (dma->broken_hdma) { if (dma_pulse_DRQ(dma->num, dma_buf + 1) != DMA_DACK) { S_printf("SB: DMA (broken) %i doesn't DACK!\n", dma->num); return 0; } } } if (!dma->input) dspio_put_dma_data(state, dma_buf, dma->is16bit); return 1; }
static int dspio_put_input_sample(struct dspio_state *state, void *ptr, int is16bit) { int ret; if (!sb_input_enabled()) return 0; if (dspio_input_fifo_filled(state)) { S_printf("SB: ERROR: input fifo overflow\n"); return 0; } if (is16bit) { ret = rng_put(&state->fifo_in, ptr); } else { Bit16u tmp = *(Bit8u *) ptr; ret = rng_put(&state->fifo_in, &tmp); } 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; }
static int midopipe_init(void *arg) { char *name = DOSEMU_MIDI_PATH; mkfifo(name, 0666); pipe_fd = RPT_SYSCALL(open(name, O_WRONLY | O_NONBLOCK)); if (pipe_fd == -1) { int err = errno; S_printf("%s: unable to open %s for writing (%s)%s\n", midopipe_name, name, strerror(errno), errno == ENXIO ? ", will continue trying" : ""); if (err == ENXIO) { /* no FIFO readers */ return 1; } else { /* some other problem */ return 0; } } /* open ok */ return 1; }
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); }
static void get_dma_params(struct dspio_dma *dma) { int dma_16bit = sb_dma_16bit(); int dma_num = dma_16bit ? sb_get_hdma_num() : sb_get_dma_num(); int broken_hdma = (dma_16bit && dma_num == -1); if (broken_hdma) { dma_num = sb_get_dma_num(); S_printf("SB: Warning: HDMA is broken, using 8-bit DMA channel %i\n", dma_num); } dma->num = dma_num; dma->is16bit = dma_16bit; dma->broken_hdma = broken_hdma; dma->rate = sb_get_dma_sampling_rate(); dma->stereo = sb_dma_samp_stereo(); dma->samp_signed = sb_dma_samp_signed(); dma->input = sb_dma_input(); dma->silence = sb_dma_silence(); dma->dsp_fifo_enabled = sb_fifo_enabled(); }
static void process_samples(long long now, int min_buf) { int nframes, retry; double period, mf_time_cur; mf_time_cur = pcm_time_lock(pcm_stream); do { retry = 0; period = pcm_frame_period_us(flus_srate); nframes = (now - mf_time_cur) / period; if (nframes > FLUS_MAX_BUF) { nframes = FLUS_MAX_BUF; retry = 1; } if (nframes >= min_buf) { mf_process_samples(nframes); mf_time_cur = pcm_get_stream_time(pcm_stream); if (debug_level('S') >= 5) S_printf("MIDI: processed %i samples with fluidsynth\n", nframes); } } while (retry); pcm_time_unlock(pcm_stream); }
static int midotmdty_detect(void) { char buf[255]; int status, ret; if (!midotmdty_preinit()) return FALSE; ret = midotmdty_check_ready(buf, sizeof(buf), 0); if (ret) { const char *ver_str = "Server Version "; char *ptr = strstr(buf, ver_str); int vmin, vmid, vmaj, ver; if (!ptr) { ret = FALSE; } else { ptr += strlen(ver_str); sscanf(ptr, "%d.%d.%d", &vmaj, &vmid, &vmin); ver = vmaj * 10000 + vmid * 100 + vmin; if (ver < 10004) ret = FALSE; } if (!ret) S_printf ("[ Note: TiMidity++ found but is too old, please update. ]\n"); } if (!ret) { close(data_sock); close(ctrl_sock_out); if (tmdty_pid != -1) { waitpid(tmdty_pid, &status, 0); tmdty_pid = -1; } } return ret; }