static int32_t Padsynth_vstate_render_voice( Voice_state* vstate, Proc_state* proc_state, const Device_thread_state* proc_ts, const Au_state* au_state, const Work_buffers* wbs, int32_t buf_start, int32_t buf_stop, double tempo) { rassert(vstate != NULL); rassert(proc_state != NULL); rassert(proc_ts != NULL); rassert(au_state != NULL); rassert(wbs != NULL); rassert(tempo > 0); if (buf_start == buf_stop) return buf_start; const Device_state* dstate = &proc_state->parent; Padsynth_vstate* ps_vstate = (Padsynth_vstate*)vstate; const Proc_padsynth* ps = (const Proc_padsynth*)dstate->device->dimpl; if (ps->sample_map == NULL) { vstate->active = false; return buf_start; } // Get frequencies Work_buffer* freqs_wb = Device_thread_state_get_voice_buffer( proc_ts, DEVICE_PORT_TYPE_RECV, PORT_IN_PITCH); Work_buffer* pitches_wb = freqs_wb; if (isnan(ps_vstate->init_pitch)) ps_vstate->init_pitch = (pitches_wb != NULL) ? Work_buffer_get_contents(pitches_wb)[buf_start] : 0; if (freqs_wb == NULL) freqs_wb = Work_buffers_get_buffer_mut(wbs, PADSYNTH_WB_FIXED_PITCH); Proc_fill_freq_buffer(freqs_wb, pitches_wb, buf_start, buf_stop); const float* freqs = Work_buffer_get_contents(freqs_wb); // Get volume scales Work_buffer* scales_wb = Device_thread_state_get_voice_buffer( proc_ts, DEVICE_PORT_TYPE_RECV, PORT_IN_FORCE); Work_buffer* dBs_wb = scales_wb; if (scales_wb == NULL) scales_wb = Work_buffers_get_buffer_mut(wbs, PADSYNTH_WB_FIXED_FORCE); Proc_fill_scale_buffer(scales_wb, dBs_wb, buf_start, buf_stop); const float* scales = Work_buffer_get_contents(scales_wb); // Get output buffer for writing float* out_bufs[2] = { NULL }; Proc_state_get_voice_audio_out_buffers( proc_ts, PORT_OUT_AUDIO_L, PORT_OUT_COUNT, out_bufs); // Choose our sample const Padsynth_sample_entry* entry = Padsynth_sample_map_get_entry(ps->sample_map, ps_vstate->init_pitch); if (entry == NULL) { vstate->active = false; return buf_start; } // Render audio const float* sample_buf = Sample_get_buffer(entry->sample, 0); const int32_t length = Padsynth_sample_map_get_sample_length(ps->sample_map); const int32_t sample_rate = PADSYNTH_DEFAULT_AUDIO_RATE; const double sample_freq = cents_to_Hz(entry->center_pitch); const double audio_rate = dstate->audio_rate; const double init_pos = fmod(ps_vstate->pos, length); // the length may have changed bool is_state_pos_updated = false; for (int32_t ch = 0; ch < 2; ++ch) { float* out_buf = out_bufs[ch]; if (out_buf == NULL) continue; double pos = init_pos; if (ps->is_stereo_enabled && is_state_pos_updated) { pos += (length / 2); if (pos >= length) pos -= length; } for (int32_t i = buf_start; i < buf_stop; ++i) { const float freq = freqs[i]; const float scale = scales[i]; const int32_t pos1 = (int32_t)pos; const int32_t pos2 = pos1 + 1; const double lerp_val = pos - floor(pos); const float item1 = sample_buf[pos1]; const float item2 = sample_buf[pos2]; const float value = (float)lerp(item1, item2, lerp_val); out_buf[i] = value * scale; pos += (freq / sample_freq) * (sample_rate / audio_rate); while (pos >= length) pos -= length; } if (!ps->is_stereo_enabled || !is_state_pos_updated) { ps_vstate->pos = pos; is_state_pos_updated = true; } } if (ps->is_ramp_attack_enabled) Proc_ramp_attack(vstate, 2, out_bufs, buf_start, buf_stop, dstate->audio_rate); return buf_stop; }
int32_t Debug_vstate_render_voice( Voice_state* vstate, Proc_state* proc_state, const Device_thread_state* proc_ts, const Au_state* au_state, const Work_buffers* wbs, int32_t frame_count, double tempo) { rassert(vstate != NULL); rassert(proc_state != NULL); rassert(proc_ts != NULL); rassert(au_state != NULL); rassert(wbs != NULL); rassert(frame_count > 0); rassert(tempo > 0); const Processor* proc = (const Processor*)proc_state->parent.device; // Get pitches const Cond_work_buffer* actual_pitches = Cond_work_buffer_init( COND_WORK_BUFFER_AUTO, Device_thread_state_get_voice_buffer( proc_ts, DEVICE_PORT_TYPE_RECV, 0, NULL), 0); // Get output buffers for writing float* out_buffer = NULL; { Work_buffer* out_wb = Device_thread_state_get_voice_buffer( proc_ts, DEVICE_PORT_TYPE_SEND, 0, NULL); if (out_wb != NULL) { rassert(Work_buffer_get_sub_count(out_wb) == 2); rassert(Work_buffer_get_stride(out_wb) == 2); out_buffer = Work_buffer_get_contents_mut(out_wb, 0); Work_buffer_mark_valid(out_wb, 0); Work_buffer_mark_valid(out_wb, 1); } } Proc_debug* debug = (Proc_debug*)proc->parent.dimpl; if (debug->single_pulse) { if (vstate->pos == 1) { vstate->active = false; return 0; } const float val = 1.0; if (out_buffer != NULL) { out_buffer[0] = val; out_buffer[1] = val; } // We want all single pulses to be included in test buffers, // even if another voice replaces us in the channel foreground Voice_state_set_keep_alive_stop(vstate, 1); vstate->pos = 1; return 1; } if ((vstate->pos >= 10) || (!vstate->note_on && vstate->noff_pos_rem >= 2)) { vstate->active = false; return 0; } const int32_t audio_rate = proc_state->parent.audio_rate; for (int32_t i = 0; i < frame_count; ++i) { const double freq = cents_to_Hz( Cond_work_buffer_get_value(actual_pitches, i)); double vals[KQT_BUFFERS_MAX] = { 0 }; if (vstate->rel_pos == 0) { vals[0] = vals[1] = 1.0; vstate->rel_pos = 1; } else { vals[0] = vals[1] = 0.5; } if (!vstate->note_on) { vals[0] = -vals[0]; vals[1] = -vals[1]; } if (out_buffer != NULL) { out_buffer[i * 2] = (float)vals[0]; out_buffer[i * 2 + 1] = (float)vals[1]; } vstate->rel_pos_rem += freq / audio_rate; if (!vstate->note_on) { vstate->noff_pos_rem += freq / audio_rate; if (vstate->noff_pos_rem >= 2) { Voice_state_set_keep_alive_stop(vstate, i + 1); return i + 1; } } if (vstate->rel_pos_rem >= 1) { ++vstate->pos; if (vstate->pos >= 10) { Voice_state_set_keep_alive_stop(vstate, i + 1); return i + 1; } vstate->rel_pos = 0; vstate->rel_pos_rem -= floor(vstate->rel_pos_rem); } } Voice_state_set_keep_alive_stop(vstate, frame_count); return frame_count; }
static int32_t Debug_vstate_render_voice( Voice_state* vstate, Proc_state* proc_state, const Device_thread_state* proc_ts, const Au_state* au_state, const Work_buffers* wbs, int32_t buf_start, int32_t buf_stop, double tempo) { rassert(vstate != NULL); rassert(proc_state != NULL); rassert(proc_ts != NULL); rassert(au_state != NULL); rassert(wbs != NULL); rassert(tempo > 0); const Processor* proc = (const Processor*)proc_state->parent.device; // Get pitches const Cond_work_buffer* actual_pitches = Cond_work_buffer_init( COND_WORK_BUFFER_AUTO, Device_thread_state_get_voice_buffer(proc_ts, DEVICE_PORT_TYPE_RECV, 0), 0); // Get output buffers for writing float* out_buffers[2] = { NULL }; Proc_state_get_voice_audio_out_buffers(proc_ts, 0, 2, out_buffers); Proc_debug* debug = (Proc_debug*)proc->parent.dimpl; if (debug->single_pulse) { if (buf_start < buf_stop) { const float val = 1.0; if (out_buffers[0] != NULL) out_buffers[0][buf_start] = val; if (out_buffers[1] != NULL) out_buffers[1][buf_start] = val; Voice_state_set_finished(vstate); // We want all single pulses to be included in test buffers, // even if another voice replaces us in the channel foreground Voice_state_mark_release_data(vstate, buf_start + 1); return buf_start + 1; } return buf_start; } const int32_t audio_rate = proc_state->parent.audio_rate; for (int32_t i = buf_start; i < buf_stop; ++i) { const double freq = cents_to_Hz( Cond_work_buffer_get_value(actual_pitches, i)); double vals[KQT_BUFFERS_MAX] = { 0 }; if (vstate->rel_pos == 0) { vals[0] = vals[1] = 1.0; vstate->rel_pos = 1; } else { vals[0] = vals[1] = 0.5; } if (!vstate->note_on) { vals[0] = -vals[0]; vals[1] = -vals[1]; Voice_state_mark_release_data(vstate, i + 1); } if (out_buffers[0] != NULL) out_buffers[0][i] = (float)vals[0]; if (out_buffers[1] != NULL) out_buffers[1][i] = (float)vals[1]; vstate->rel_pos_rem += freq / audio_rate; if (!vstate->note_on) { vstate->noff_pos_rem += freq / audio_rate; if (vstate->noff_pos_rem >= 2) { Voice_state_set_finished(vstate); return i + 1; } } if (vstate->rel_pos_rem >= 1) { ++vstate->pos; if (vstate->pos >= 10) { Voice_state_set_finished(vstate); return i + 1; } vstate->rel_pos = 0; vstate->rel_pos_rem -= floor(vstate->rel_pos_rem); } } return buf_stop; }