//----------------------------------------------------------------------------- static void timer_set_period(uint16_t i) { TC0->COUNT16.CC[0].reg = (F_CPU / 1000ul / 256) * i; timer_sync(); TC0->COUNT16.COUNT.reg = 0; timer_sync(); }
static size_t httpd_output_play(void *data, const void *chunk, size_t size, GError **error) { struct httpd_output *httpd = data; bool has_clients; g_mutex_lock(httpd->mutex); has_clients = httpd->clients != NULL; g_mutex_unlock(httpd->mutex); if (has_clients) { bool success; success = httpd_output_encode_and_play(httpd, chunk, size, error); if (!success) return 0; } if (!httpd->timer->started) timer_start(httpd->timer); else timer_sync(httpd->timer); timer_add(httpd->timer, size); return size; }
//----------------------------------------------------------------------------- static void timer_init(void) { PM->APBCMASK.reg |= PM_APBCMASK_TC0; GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC0_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0); TC0->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_PRESCSYNC_RESYNC; timer_sync(); TC0->COUNT16.COUNT.reg = 0; timer_sync(); timer_set_period(PERIOD_SLOW); TC0->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; timer_sync(); TC0->COUNT16.INTENSET.reg = TC_INTENSET_MC(1); NVIC_EnableIRQ(TC0_IRQn); }
static size_t openal_play(void *data, const void *chunk, size_t size, G_GNUC_UNUSED GError **error) { struct openal_data *od = data; ALuint buffer; ALint num, state; if (alcGetCurrentContext() != od->context) { alcMakeContextCurrent(od->context); } alGetSourcei(od->source, AL_BUFFERS_PROCESSED, &num); if (od->filled < NUM_BUFFERS) { /* fill all buffers */ buffer = od->buffers[od->filled]; od->filled++; } else { /* wait for processed buffer */ while (num < 1) { if (!od->timer->started) { timer_start(od->timer); } else { timer_sync(od->timer); } timer_add(od->timer, size); alGetSourcei(od->source, AL_BUFFERS_PROCESSED, &num); } alSourceUnqueueBuffers(od->source, 1, &buffer); } alBufferData(buffer, od->format, chunk, size, od->frequency); alSourceQueueBuffers(od->source, 1, &buffer); alGetSourcei(od->source, AL_SOURCE_STATE, &state); if (state != AL_PLAYING) { alSourcePlay(od->source); } return size; }
static size_t fifo_output_play(void *data, const void *chunk, size_t size, GError **error) { struct fifo_data *fd = (struct fifo_data *)data; ssize_t bytes; if (!fd->timer->started) timer_start(fd->timer); else timer_sync(fd->timer); timer_add(fd->timer, size); while (true) { bytes = write(fd->output, chunk, size); if (bytes > 0) return (size_t)bytes; if (bytes < 0) { switch (errno) { case EAGAIN: /* The pipe is full, so empty it */ fifo_output_cancel(fd); continue; case EINTR: continue; } g_set_error(error, fifo_output_quark(), errno, "Failed to write to FIFO %s: %s", fd->path, g_strerror(errno)); return 0; } } }
static void fluidsynth_file_decode(struct decoder *decoder, const char *path_fs) { static const struct audio_format audio_format = { .sample_rate = 48000, .bits = 16, .channels = 2, }; char setting_sample_rate[] = "synth.sample-rate"; /* char setting_verbose[] = "synth.verbose"; char setting_yes[] = "yes"; */ const char *soundfont_path; fluid_settings_t *settings; fluid_synth_t *synth; fluid_player_t *player; char *path_dup; int ret; Timer *timer; enum decoder_command cmd; soundfont_path = config_get_string("soundfont", "/usr/share/sounds/sf2/FluidR3_GM.sf2"); /* set up fluid settings */ settings = new_fluid_settings(); if (settings == NULL) return; fluid_settings_setnum(settings, setting_sample_rate, 48000); /* fluid_settings_setstr(settings, setting_verbose, setting_yes); */ /* create the fluid synth */ synth = new_fluid_synth(settings); if (synth == NULL) { delete_fluid_settings(settings); return; } ret = fluid_synth_sfload(synth, soundfont_path, true); if (ret < 0) { g_warning("fluid_synth_sfload() failed"); delete_fluid_synth(synth); delete_fluid_settings(settings); return; } /* create the fluid player */ player = new_fluid_player(synth); if (player == NULL) { delete_fluid_synth(synth); delete_fluid_settings(settings); return; } /* temporarily duplicate the path_fs string, because fluidsynth wants a writable string */ path_dup = g_strdup(path_fs); ret = fluid_player_add(player, path_dup); g_free(path_dup); if (ret != 0) { g_warning("fluid_player_add() failed"); delete_fluid_player(player); delete_fluid_synth(synth); delete_fluid_settings(settings); return; } /* start the player */ ret = fluid_player_play(player); if (ret != 0) { g_warning("fluid_player_play() failed"); delete_fluid_player(player); delete_fluid_synth(synth); delete_fluid_settings(settings); return; } /* set up a timer for synchronization; fluidsynth always decodes in real time, which forces us to synchronize */ /* XXX is there any way to switch off real-time decoding? */ timer = timer_new(&audio_format); timer_start(timer); /* initialization complete - announce the audio format to the MPD core */ decoder_initialized(decoder, &audio_format, false, -1); do { int16_t buffer[2048]; const unsigned max_frames = G_N_ELEMENTS(buffer) / 2; /* synchronize with the fluid player */ timer_add(timer, sizeof(buffer)); timer_sync(timer); /* read samples from fluidsynth and send them to the MPD core */ ret = fluid_synth_write_s16(synth, max_frames, buffer, 0, 2, buffer, 1, 2); /* XXX how do we see whether the player is done? We can't access the private attribute player->status */ if (ret != 0) break; cmd = decoder_data(decoder, NULL, buffer, sizeof(buffer), 0, 0, NULL); } while (cmd == DECODE_COMMAND_NONE); /* clean up */ timer_free(timer); fluid_player_stop(player); fluid_player_join(player); delete_fluid_player(player); delete_fluid_synth(synth); delete_fluid_settings(settings); } static struct tag * fluidsynth_tag_dup(const char *file) { struct tag *tag = tag_new(); /* to be implemented */ (void)file; return tag; } static const char *const fluidsynth_suffixes[] = { "mid", NULL }; const struct decoder_plugin fluidsynth_decoder_plugin = { .name = "fluidsynth", .init = fluidsynth_init, .file_decode = fluidsynth_file_decode, .tag_dup = fluidsynth_tag_dup, .suffixes = fluidsynth_suffixes, };
void game_step(Game* game) { cpSpaceStep(game->scene->space, game->timer->dt); timer_sync(game->timer); }