static void Effect_process( const Device* device, Device_states* states, uint32_t start, uint32_t until, uint32_t freq, double tempo) { assert(device != NULL); assert(states != NULL); assert(freq > 0); assert(isfinite(tempo)); Effect_state* eff_state = (Effect_state*)Device_states_get_state( states, Device_get_id(device)); const Effect* eff = (const Effect*)device; if (eff_state->bypass) { Device_state* ds = Device_states_get_state( states, Device_get_id((const Device*)device)); mix_interface_connection(ds, ds, start, until); } else if (eff->connections != NULL) { #ifndef NDEBUG static bool in_effect = false; assert(!in_effect); in_effect = true; #endif Connections_clear_buffers(eff->connections, states, start, until); // Fill input interface buffers Device_state* ds = Device_states_get_state( states, Device_get_id((const Device*)device)); Device_state* in_iface_ds = Device_states_get_state( states, Device_get_id(Effect_get_input_interface(eff))); mix_interface_connection(in_iface_ds, ds, start, until); // Process effect graph Connections_mix(eff->connections, states, start, until, freq, tempo); // Fill output interface buffers Device_state* out_iface_ds = Device_states_get_state( states, Device_get_id(Effect_get_output_interface(eff))); mix_interface_connection(ds, out_iface_ds, start, until); #ifndef NDEBUG in_effect = false; #endif } return; }
static void Au_state_fire_event( Device_state* dstate, const char* event_name, const Value* arg, Random* rand) { rassert(dstate != NULL); rassert(event_name != NULL); rassert(arg != NULL); rassert(rand != NULL); const Audio_unit* au = (const Audio_unit*)dstate->device; const Au_event_map* map = Audio_unit_get_event_map(au); if (map == NULL) return; const Proc_table* procs = Audio_unit_get_procs(au); Au_event_iter* iter = AU_EVENT_ITER_AUTO; Au_event_iter_result* result = Au_event_iter_init(iter, map, event_name, arg, rand); while (result != NULL) { rassert(result->dev_type == AU_EVENT_TARGET_DEV_PROC); const Device* device = (const Device*)Proc_table_get_proc(procs, result->dev_index); if (device != NULL) { Device_states* dstates = ((Au_state*)dstate)->dstates; Device_state* pstate = Device_states_get_state(dstates, Device_get_id(device)); Device_state_fire_event(pstate, result->event_name, &result->arg, rand); } result = Au_event_iter_get_next(iter); } return; }
static Device_state* get_target_dstate( const Audio_unit* au, Device_states* dstates, const char* stream_name) { rassert(au != NULL); rassert(dstates != NULL); rassert(stream_name != NULL); const Au_streams* streams = Audio_unit_get_streams(au); if (streams == NULL) return NULL; const int proc_index = Au_streams_get_target_proc_index(streams, stream_name); if (proc_index < 0) return NULL; const Processor* proc = Audio_unit_get_proc(au, proc_index); if ((proc == NULL) || !Device_is_existent((const Device*)proc)) return NULL; Device_state* dstate = Device_states_get_state(dstates, Device_get_id((const Device*)proc)); if (Device_impl_get_proc_type(dstate->device->dimpl) != Proc_type_stream) return NULL; return dstate; }
bool Device_sync_states(const Device* device, Device_states* dstates) { assert(device != NULL); assert(dstates != NULL); if (device->dimpl != NULL) { Device_state* dstate = Device_states_get_state( dstates, Device_get_id(device)); Device_params_iter* iter = Device_params_iter_init( DEVICE_PARAMS_ITER_AUTO, device->dparams); const char* key = Device_params_iter_get_next_key(iter); while (key != NULL) { if (!Device_impl_set_state_key(device->dimpl, dstate, key)) return false; key = Device_params_iter_get_next_key(iter); } } return true; }
static bool init_effect_buffers(Device_states* dstates, const Device_node* node) { rassert(dstates != NULL); rassert(node != NULL); const Device* node_device = Device_node_get_device(node); if (node_device == NULL) return true; Device_thread_state* node_ts = Device_states_get_thread_state(dstates, 0, Device_get_id(node_device)); if (Device_thread_state_get_node_state(node_ts) > DEVICE_NODE_STATE_NEW) { rassert(Device_thread_state_get_node_state(node_ts) != DEVICE_NODE_STATE_REACHED); return true; } Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_REACHED); if (Device_node_get_type(node) == DEVICE_NODE_TYPE_AU) { const Audio_unit* au = Device_node_get_au_mut(node); if (au == NULL) { Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_VISITED); return true; } const Connections* au_conns = Audio_unit_get_connections(au); if (au_conns != NULL) { if (!Device_states_prepare(dstates, au_conns)) return false; } } for (int port = 0; port < KQT_DEVICE_PORTS_MAX; ++port) { const Connection* edge = Device_node_get_received(node, port); while (edge != NULL) { if (Device_node_get_device(edge->node) == NULL) { edge = edge->next; continue; } if (!init_effect_buffers(dstates, edge->node)) return false; edge = edge->next; } } Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_VISITED); return true; }
static void DSP_gc_process( const Device* device, Device_states* states, uint32_t start, uint32_t until, uint32_t freq, double tempo) { assert(device != NULL); assert(states != NULL); assert(freq > 0); assert(tempo > 0); Device_state* ds = Device_states_get_state(states, Device_get_id(device)); assert(ds != NULL); (void)freq; (void)tempo; DSP_gc* gc = (DSP_gc*)device->dimpl; //assert(string_eq(gc->parent.type, "gaincomp")); kqt_frame* in_data[] = { NULL, NULL }; kqt_frame* out_data[] = { NULL, NULL }; DSP_get_raw_input(ds, 0, in_data); DSP_get_raw_output(ds, 0, out_data); if (gc->map != NULL) { for (uint32_t i = start; i < until; ++i) { kqt_frame val_l = fabs(in_data[0][i]); kqt_frame val_r = fabs(in_data[1][i]); val_l = Envelope_get_value(gc->map, min(val_l, 1)); val_r = Envelope_get_value(gc->map, min(val_r, 1)); if (in_data[0][i] < 0) val_l = -val_l; if (in_data[1][i] < 0) val_r = -val_r; out_data[0][i] += val_l; out_data[1][i] += val_r; assert(!isnan(out_data[0][i]) || isnan(in_data[0][i])); assert(!isnan(out_data[0][i]) || isnan(in_data[1][i])); } } else { for (uint32_t i = start; i < until; ++i) { out_data[0][i] += in_data[0][i]; out_data[1][i] += in_data[1][i]; } } return; }
static void DSP_freeverb_process( const Device* device, Device_states* states, uint32_t start, uint32_t until, uint32_t freq, double tempo) { assert(device != NULL); assert(states != NULL); assert(freq > 0); assert(tempo > 0); (void)freq; (void)tempo; Freeverb_state* fstate = (Freeverb_state*)Device_states_get_state( states, Device_get_id(device)); DSP_freeverb* freeverb = (DSP_freeverb*)device->dimpl; //assert(string_eq(freeverb->parent.type, "freeverb")); kqt_frame* in_data[] = { NULL, NULL }; kqt_frame* out_data[] = { NULL, NULL }; DSP_get_raw_input(&fstate->parent.parent, 0, in_data); DSP_get_raw_output(&fstate->parent.parent, 0, out_data); for (uint32_t i = start; i < until; ++i) { kqt_frame out_l = 0; kqt_frame out_r = 0; kqt_frame input = (in_data[0][i] + in_data[1][i]) * freeverb->gain; for (int comb = 0; comb < FREEVERB_COMBS; ++comb) { out_l += Freeverb_comb_process(fstate->comb_left[comb], input); out_r += Freeverb_comb_process(fstate->comb_right[comb], input); } for (int allpass = 0; allpass < FREEVERB_ALLPASSES; ++allpass) { out_l = Freeverb_allpass_process( fstate->allpass_left[allpass], out_l); out_r = Freeverb_allpass_process( fstate->allpass_right[allpass], out_r); } out_data[0][i] += out_l * freeverb->wet1 + out_r * freeverb->wet2 /* + in_data[0][i] * freeverb->dry */; out_data[1][i] += out_r * freeverb->wet1 + out_l * freeverb->wet2 /* + in_data[1][i] * freeverb->dry */; } return; }
bool Device_set_state_key( const Device* device, Device_states* dstates, const char* key) { assert(device != NULL); assert(dstates != NULL); assert(key != NULL); assert(string_has_prefix(key, "i/") || string_has_prefix(key, "c/")); if (device->dimpl != NULL) { Device_state* dstate = Device_states_get_state( dstates, Device_get_id(device)); return Device_impl_set_state_key(device->dimpl, dstate, key + 2); } return true; }
static void Effect_reset(const Device* device, Device_states* dstates) { assert(device != NULL); assert(dstates != NULL); // Reset DSPs const Effect* eff = (const Effect*)device; for (int i = 0; i < KQT_DSPS_MAX; ++i) { const DSP* dsp = DSP_table_get_dsp(eff->dsps, i); if (dsp != NULL) Device_reset((const Device*)dsp, dstates); } // Reset Effect state Effect_state* eff_state = (Effect_state*)Device_states_get_state( dstates, Device_get_id(device)); Effect_state_reset(eff_state); return; }
static bool init_buffers(Device_states* dstates, const Device_node* node) { rassert(dstates != NULL); rassert(node != NULL); const Device* node_device = Device_node_get_device(node); if (node_device == NULL) return true; Device_thread_state* node_ts = Device_states_get_thread_state(dstates, 0, Device_get_id(node_device)); rassert(Device_thread_state_get_node_state(node_ts) != DEVICE_NODE_STATE_REACHED); if (Device_thread_state_get_node_state(node_ts) == DEVICE_NODE_STATE_VISITED) return true; Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_REACHED); for (int port = 0; port < KQT_DEVICE_PORTS_MAX; ++port) { const Connection* edge = Device_node_get_received(node, port); while (edge != NULL) { rassert(edge->node != NULL); const Device* send_device = Device_node_get_device(edge->node); if (send_device == NULL || !Device_has_complete_type(send_device) || !Device_get_port_existence( node_device, DEVICE_PORT_TYPE_RECV, port) || !Device_get_port_existence( send_device, DEVICE_PORT_TYPE_SEND, edge->port)) { edge = edge->next; continue; } /* if (!Device_get_port_existence( node_device, DEVICE_PORT_TYPE_RECV, port)) fprintf(stderr, "Warning: connecting to non-existent port %d of device %s\n", port, node->name); if (!Device_get_port_existence( send_device, DEVICE_PORT_TYPE_SEND, edge->port)) fprintf(stderr, "Warning: connecting from non-existent port %d of device %s\n", edge->port, edge->node->name); // */ // Add receive buffers const uint32_t recv_id = Device_get_id(node_device); if (!Device_states_add_audio_buffer( dstates, recv_id, DEVICE_PORT_TYPE_RECV, port)) return false; // Add send buffers const uint32_t send_id = Device_get_id(send_device); if (!Device_states_add_audio_buffer( dstates, send_id, DEVICE_PORT_TYPE_SEND, edge->port)) return false; // Recurse to the sender if (!init_buffers(dstates, edge->node)) return false; edge = edge->next; } } Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_VISITED); return true; }
bool Event_channel_hit_process( Channel* ch, Device_states* dstates, const Master_params* master_params, const Event_params* params) { rassert(ch != NULL); rassert(ch->audio_rate > 0); rassert(ch->tempo > 0); rassert(dstates != NULL); rassert(master_params != NULL); rassert(params != NULL); rassert(params->arg != NULL); rassert(params->arg->type == VALUE_TYPE_INT); // Move the old Voices to the background Event_channel_note_off_process(ch, dstates, master_params, NULL); // Find our audio unit Audio_unit* au = Module_get_au_from_input(ch->parent.module, ch->au_input); if (au == NULL) return true; init_force_controls(ch, master_params); // Don't attempt to hit effects if (Audio_unit_get_type(au) != AU_TYPE_INSTRUMENT) return true; const int hit_index = (int)params->arg->value.int_type; if (!Audio_unit_get_hit_existence(au, hit_index)) return true; const Param_proc_filter* hpf = Audio_unit_get_hit_proc_filter(au, hit_index); // Generate our next note random seed here so that random generation // is consistent even if we run out of voices const uint64_t note_rand_seed = Random_get_uint64(&ch->rand); // Find reserved voices Voice_group* vgroup = VOICE_GROUP_AUTO; if (!Voice_group_reservations_get_clear_entry( ch->voice_group_res, ch->num, &ch->fg_group_id) || (Voice_pool_get_group(ch->pool, ch->fg_group_id, vgroup) == NULL)) { reset_channel_voices(ch); return true; } int voice_index = 0; for (int i = 0; i < KQT_PROCESSORS_MAX; ++i) { const Processor* proc = Audio_unit_get_proc(au, i); if (proc == NULL || !Device_is_existent((const Device*)proc) || !Processor_get_voice_signals(proc)) continue; // Skip processors that are filtered out for this hit index if ((hpf != NULL) && !Param_proc_filter_is_proc_allowed(hpf, i)) continue; const Proc_state* proc_state = (Proc_state*)Device_states_get_state( dstates, Device_get_id((const Device*)proc)); Voice_state_get_size_func* get_vstate_size = proc_state->parent.device->dimpl->get_vstate_size; if ((get_vstate_size != NULL) && (get_vstate_size() == 0)) continue; char context_str[16] = ""; snprintf(context_str, 16, "np%hd", (short)i); Random* random = Random_init(RANDOM_AUTO, context_str); Random_set_seed(random, note_rand_seed); const uint64_t voice_rand_seed = Random_get_uint64(random); Voice* voice = Voice_group_get_voice(vgroup, voice_index); const bool voice_allocated = init_voice( ch, voice, au, ch->fg_group_id, proc_state, i, voice_rand_seed); if (!voice_allocated) { // Some of our voices were reallocated reset_channel_voices(ch); return true; } ++voice_index; Voice_state* vs = voice->state; vs->hit_index = hit_index; if (vs->proc_type == Proc_type_force) { Force_controls* fc = Force_vstate_get_force_controls_mut(vs); Force_controls_copy(fc, &ch->force_controls); } } Channel_reset_test_output(ch); init_streams(ch, au); return true; }
bool Event_channel_note_on_process( Channel* ch, Device_states* dstates, const Master_params* master_params, const Event_params* params) { rassert(ch != NULL); rassert(ch->audio_rate > 0); rassert(ch->tempo > 0); rassert(dstates != NULL); rassert(master_params != NULL); rassert(params != NULL); rassert(params->arg != NULL); rassert(params->arg->type == VALUE_TYPE_FLOAT); // Move the old Voices to the background Event_channel_note_off_process(ch, dstates, master_params, NULL); // Find our audio unit Audio_unit* au = Module_get_au_from_input(ch->parent.module, ch->au_input); if (au == NULL) return true; double pitch_param = params->arg->value.float_type; // Retune pitch parameter if a retuner is active { const int tuning_index = master_params->cur_tuning_state; if (0 <= tuning_index && tuning_index < KQT_TUNING_TABLES_MAX) { Tuning_state* state = master_params->tuning_states[tuning_index]; const Tuning_table* table = Module_get_tuning_table(master_params->parent.module, tuning_index); if (state != NULL && table != NULL) pitch_param = Tuning_state_get_retuned_pitch(state, table, pitch_param); } } if (ch->carry_pitch) { if (isnan(ch->pitch_controls.pitch)) ch->pitch_controls.pitch = pitch_param; if (isnan(ch->pitch_controls.orig_carried_pitch)) ch->pitch_controls.orig_carried_pitch = pitch_param; const double pitch_diff = pitch_param - ch->pitch_controls.orig_carried_pitch; ch->pitch_controls.pitch_add = pitch_diff; } else { Pitch_controls_reset(&ch->pitch_controls); ch->pitch_controls.orig_carried_pitch = pitch_param; Slider_set_tempo(&ch->pitch_controls.slider, master_params->tempo); Slider_set_length(&ch->pitch_controls.slider, &ch->pitch_slide_length); LFO_set_tempo(&ch->pitch_controls.vibrato, master_params->tempo); LFO_set_speed_slide(&ch->pitch_controls.vibrato, &ch->vibrato_speed_slide); LFO_set_depth_slide(&ch->pitch_controls.vibrato, &ch->vibrato_depth_slide); ch->pitch_controls.pitch = pitch_param; if (isnan(ch->pitch_controls.orig_carried_pitch)) ch->pitch_controls.orig_carried_pitch = pitch_param; } init_force_controls(ch, master_params); // Don't attempt to play effects if (Audio_unit_get_type(au) != AU_TYPE_INSTRUMENT) return true; // Generate our next note random seed here so that random generation // is consistent even if we run out of voices const uint64_t note_rand_seed = Random_get_uint64(&ch->rand); // Find reserved voices Voice_group* vgroup = VOICE_GROUP_AUTO; if (!Voice_group_reservations_get_clear_entry( ch->voice_group_res, ch->num, &ch->fg_group_id) || (Voice_pool_get_group(ch->pool, ch->fg_group_id, vgroup) == NULL)) { reset_channel_voices(ch); return true; } int voice_index = 0; for (int i = 0; i < KQT_PROCESSORS_MAX; ++i) { const Processor* proc = Audio_unit_get_proc(au, i); if (proc == NULL || !Device_is_existent((const Device*)proc) || !Processor_get_voice_signals(proc)) continue; const Proc_state* proc_state = (Proc_state*)Device_states_get_state( dstates, Device_get_id((const Device*)proc)); Voice_state_get_size_func* get_vstate_size = proc_state->parent.device->dimpl->get_vstate_size; if ((get_vstate_size != NULL) && (get_vstate_size() == 0)) continue; char context_str[16] = ""; snprintf(context_str, 16, "np%hd", (short)i); Random* random = Random_init(RANDOM_AUTO, context_str); Random_set_seed(random, note_rand_seed); const uint64_t voice_rand_seed = Random_get_uint64(random); Voice* voice = Voice_group_get_voice(vgroup, voice_index); const bool voice_allocated = init_voice( ch, voice, au, ch->fg_group_id, proc_state, i, voice_rand_seed); if (!voice_allocated) { // Some of our voices were reallocated reset_channel_voices(ch); return true; } ++voice_index; Voice_state* vs = voice->state; if (vs->proc_type == Proc_type_pitch) Pitch_vstate_set_controls(vs, &ch->pitch_controls); if (vs->proc_type == Proc_type_force) { Force_controls* fc = Force_vstate_get_force_controls_mut(vs); Force_controls_copy(fc, &ch->force_controls); } } Channel_reset_test_output(ch); init_streams(ch, au); return true; }