/***************************************************************************** * * PROCESS_BUFFER() * * callback for jack to read audio data from ringbuffer * jack uses a realtime priority thread for this * *****************************************************************************/ int process_buffer(jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in1; jack_default_audio_sample_t *in2; jack_default_audio_sample_t *out1; jack_default_audio_sample_t *out2; int portion1; int portion2; int j, osc, lfo; /* Get the input and output buffers for audio data */ in1 = jack_port_get_buffer (input_port1, nframes); in2 = jack_port_get_buffer (input_port2, nframes); out1 = jack_port_get_buffer (output_port1, nframes); out2 = jack_port_get_buffer (output_port2, nframes); /* check for jack not running or global shutdown so we don't get hung on mutex */ if (!jack_running || shutdown) { return 0; } /* copy circular buffers and update index */ /* WARNING: needs to handle circular buffer properly */ if ((buffer_read_index + nframes) > buffer_size) { portion1 = buffer_size - buffer_read_index; portion2 = nframes - portion1; memcpy (&(input_buffer1[buffer_read_index]), in1, sizeof (jack_default_audio_sample_t) * portion1); memcpy (&(input_buffer2[buffer_read_index]), in2, sizeof (jack_default_audio_sample_t) * portion1); memcpy (input_buffer1, &(in1[portion1]), sizeof (jack_default_audio_sample_t) * portion2); memcpy (input_buffer2, &(in2[portion1]), sizeof (jack_default_audio_sample_t) * portion2); memcpy (out1, &(output_buffer1[buffer_read_index]), sizeof (jack_default_audio_sample_t) * portion1); memcpy (out2, &(output_buffer2[buffer_read_index]), sizeof (jack_default_audio_sample_t) * portion1); memcpy (&(out1[portion1]), output_buffer1, sizeof (jack_default_audio_sample_t) * portion2); memcpy (&(out2[portion1]), output_buffer2, sizeof (jack_default_audio_sample_t) * portion2); } else { memcpy (&(input_buffer1[buffer_read_index]), in1, sizeof (jack_default_audio_sample_t) * nframes); memcpy (&(input_buffer2[buffer_read_index]), in2, sizeof (jack_default_audio_sample_t) * nframes); memcpy (out1, &(output_buffer1[buffer_read_index]), sizeof (jack_default_audio_sample_t) * nframes); memcpy (out2, &(output_buffer2[buffer_read_index]), sizeof (jack_default_audio_sample_t) * nframes); } buffer_read_index += nframes; buffer_read_index %= buffer_size; /* Update buffer full and buffer needed counters */ buffer_full -= nframes; if(setting_jack_transport_mode) { /* jack transport sync */ jack_state = jack_transport_query (client, &jack_pos); /* reinit sync vars if transport is just started */ if((jack_prev_state == JackTransportStopped) && (jack_state == JackTransportStarting)) { #ifdef EXTRA_DEBUG if (debug) { fprintf (stderr, "Starting sync.\n"); } #endif need_resync = 1; } if(jack_state == JackTransportRolling) { if(need_resync) { prev_frame = jack_pos.frame - nframes; frames_per_beat = sample_rate / global.bps; frames_per_tick = sample_rate / (jack_pos.ticks_per_beat * global.bps); current_frame = 0; need_resync = 0; } /* Handle BPM change */ if(jack_pos.beats_per_minute && (global.bps != jack_pos.beats_per_minute / 60.0)) { param[0].cc_val[program_number] = jack_pos.beats_per_minute - 64; param[0].callback (main_window, (gpointer)(&(param[0]))); } /* frame-based sync */ current_frame = (jack_pos.frame - prev_frame); prev_frame = jack_pos.frame; if(current_frame != nframes) { /* whoooaaaa, we're traveling through time! */ phase_correction = current_frame - nframes; } /* do the actual sync */ if(phase_correction && (setting_jack_transport_mode == JACK_TRANSPORT_TNP)) { #ifdef EXTRA_DEBUG if (debug) { fprintf (stderr, "Out of sync. Phase correction: %d\n", phase_correction); } #endif part.delay_write_index += phase_correction; while(part.delay_write_index < 0.0) part.delay_write_index += part.delay_bufsize; while(part.delay_write_index >= part.delay_bufsize) part.delay_write_index -= part.delay_bufsize; part.chorus_lfo_index_a += phase_correction * part.chorus_lfo_adjust; while(part.chorus_lfo_index_a < 0.0) part.chorus_lfo_index_a += F_WAVEFORM_SIZE; while(part.chorus_lfo_index_a >= F_WAVEFORM_SIZE) part.chorus_lfo_index_a -= F_WAVEFORM_SIZE; part.chorus_lfo_index_b = part.chorus_lfo_index_a + (F_WAVEFORM_SIZE * 0.25); while(part.chorus_lfo_index_b < 0.0) part.chorus_lfo_index_b += F_WAVEFORM_SIZE; while(part.chorus_lfo_index_b >= F_WAVEFORM_SIZE) part.chorus_lfo_index_b -= F_WAVEFORM_SIZE; part.chorus_lfo_index_c = part.chorus_lfo_index_a + (F_WAVEFORM_SIZE * 0.5); while(part.chorus_lfo_index_c < 0.0) part.chorus_lfo_index_c += F_WAVEFORM_SIZE; while(part.chorus_lfo_index_c >= F_WAVEFORM_SIZE) part.chorus_lfo_index_c -= F_WAVEFORM_SIZE; part.chorus_lfo_index_d = part.chorus_lfo_index_a + (F_WAVEFORM_SIZE * 0.75); while(part.chorus_lfo_index_d < 0.0) part.chorus_lfo_index_d += F_WAVEFORM_SIZE; while(part.chorus_lfo_index_d >= F_WAVEFORM_SIZE) part.chorus_lfo_index_d -= F_WAVEFORM_SIZE; for (osc = 0; osc < NUM_OSCS; osc++) { for (j = 0; j < setting_polyphony; j++) { if (patch->osc_freq_base[osc] >= FREQ_BASE_TEMPO) { switch (patch->freq_mod_type[osc]) { case MOD_TYPE_LFO: tmp_1 = part.lfo_out[patch->freq_lfo[osc]]; break; case MOD_TYPE_OSC: tmp_1 = ( voice[j].osc_out1[part.osc_freq_mod[osc]] + voice[j].osc_out2[part.osc_freq_mod[osc]] ) * 0.5; break; case MOD_TYPE_VELOCITY: tmp_1 = voice[j].velocity_coef_linear; break; default: tmp_1 = 0.0; break; } voice[j].index[osc] += phase_correction * halfsteps_to_freq_mult ( ( tmp_1 * patch->freq_lfo_amount[osc] ) + part.osc_pitch_bend[osc] + patch->osc_transpose[osc] ) * voice[j].osc_freq[osc] * wave_period; while (voice[j].index[osc] < 0.0) voice[j].index[osc] += F_WAVEFORM_SIZE; while (voice[j].index[osc] >= F_WAVEFORM_SIZE) voice[j].index[osc] -= F_WAVEFORM_SIZE; } } } for (lfo = 0; lfo < NUM_LFOS; lfo++) { if (patch->lfo_freq_base[lfo] >= FREQ_BASE_TEMPO) { part.lfo_index[lfo] += phase_correction * part.lfo_freq[lfo] * halfsteps_to_freq_mult (patch->lfo_transpose[lfo] + part.lfo_pitch_bend[lfo]) * wave_period; while (part.lfo_index[lfo] < 0.0) part.lfo_index[lfo] += F_WAVEFORM_SIZE; while (part.lfo_index[lfo] >= F_WAVEFORM_SIZE) part.lfo_index[lfo] -= F_WAVEFORM_SIZE; } } phase_correction = 0; } } else if ((jack_state == JackTransportStopped) && (jack_prev_state == JackTransportRolling)) { /* send NOTE_OFFs on transport stop */ engine_notes_off(); } jack_prev_state = jack_state; } /* if(setting_jack_transport) */ /* Signal the engine that there's space again */ if (pthread_mutex_trylock (&buffer_mutex) == 0) { pthread_cond_broadcast (&buffer_has_space); pthread_mutex_unlock (&buffer_mutex); } return 0; }
/***************************************************************************** * process_phase_sync() * * Process a phase sync internal MIDI message. Currently used for syncing * JACK Transport, this function performs phase correction for a given voice. *****************************************************************************/ void process_phase_sync(MIDI_EVENT *event, unsigned int part_num) { PART *part = get_part(part_num); PATCH_STATE *state = get_active_state(part_num); DELAY *delay = get_delay(part_num); CHORUS *chorus = get_chorus(part_num); VOICE *voice; int voice_num; int osc; int lfo; int phase_correction = event->value; sample_t f_phase_correction = (sample_t) phase_correction; sample_t tmp_1; delay->write_index += phase_correction; while (delay->write_index < 0.0) { delay->write_index += delay->bufsize; } while (delay->write_index >= delay->bufsize) { delay->write_index -= delay->bufsize; } chorus->lfo_index_a += f_phase_correction * chorus->lfo_adjust; while (chorus->lfo_index_a < 0.0) { chorus->lfo_index_a += F_WAVEFORM_SIZE; } while (chorus->lfo_index_a >= F_WAVEFORM_SIZE) { chorus->lfo_index_a -= F_WAVEFORM_SIZE; } chorus->lfo_index_b = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.25); while (chorus->lfo_index_b < 0.0) { chorus->lfo_index_b += F_WAVEFORM_SIZE; } while (chorus->lfo_index_b >= F_WAVEFORM_SIZE) { chorus->lfo_index_b -= F_WAVEFORM_SIZE; } chorus->lfo_index_c = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.5); while (chorus->lfo_index_c < 0.0) { chorus->lfo_index_c += F_WAVEFORM_SIZE; } while (chorus->lfo_index_c >= F_WAVEFORM_SIZE) { chorus->lfo_index_c -= F_WAVEFORM_SIZE; } chorus->lfo_index_d = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.75); while (chorus->lfo_index_d < 0.0) { chorus->lfo_index_d += F_WAVEFORM_SIZE; } while (chorus->lfo_index_d >= F_WAVEFORM_SIZE) { chorus->lfo_index_d -= F_WAVEFORM_SIZE; } for (voice_num = 0; voice_num < setting_polyphony; voice_num++) { voice = get_voice(part_num, voice_num); for (osc = 0; osc < NUM_OSCS; osc++) { if (state->osc_freq_base[osc] >= FREQ_BASE_TEMPO) { switch (state->freq_mod_type[osc]) { case MOD_TYPE_LFO: tmp_1 = part->lfo_out[state->freq_lfo[osc]]; break; case MOD_TYPE_OSC: tmp_1 = (voice->osc_out1[part->osc_freq_mod[osc]] + voice->osc_out2[part->osc_freq_mod[osc]]) * 0.5; break; case MOD_TYPE_VELOCITY: tmp_1 = voice->velocity_coef_linear; break; default: tmp_1 = 0.0; break; } voice->index[osc] += f_phase_correction * halfsteps_to_freq_mult((tmp_1 * state->freq_lfo_amount[osc]) + part->osc_pitch_bend[osc] + state->osc_transpose[osc] + state->voice_osc_tune[voice->id] ) * voice->osc_freq[osc] * wave_period; while (voice->index[osc] < 0.0) { voice->index[osc] += F_WAVEFORM_SIZE; } while (voice->index[osc] >= F_WAVEFORM_SIZE) { voice->index[osc] -= F_WAVEFORM_SIZE; } } } } for (lfo = 0; lfo < NUM_LFOS; lfo++) { if (state->lfo_freq_base[lfo] >= FREQ_BASE_TEMPO) { part->lfo_index[lfo] += f_phase_correction * part->lfo_freq[lfo] * halfsteps_to_freq_mult(state->lfo_transpose[lfo] + part->lfo_pitch_bend[lfo]) * wave_period; while (part->lfo_index[lfo] < 0.0) { part->lfo_index[lfo] += F_WAVEFORM_SIZE; } while (part->lfo_index[lfo] >= F_WAVEFORM_SIZE) { part->lfo_index[lfo] -= F_WAVEFORM_SIZE; } } } }