Skip to content

Commit

Permalink
Merge pull request #206 from shorepine/portamento
Browse files Browse the repository at this point in the history
Portamento
  • Loading branch information
dpwe authored Sep 7, 2024
2 parents 2f48d7e + 39ed22c commit 638d07b
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 148 deletions.
17 changes: 15 additions & 2 deletions juno.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,13 @@ class JunoPatch:
vca_gate = False # else env
vcf_neg = False # else pos
hpf = 0
portamento = 0
# Map of setup_fn: [params triggering setup]
post_set_fn = {'lfo': ['lfo_rate', 'lfo_delay_time'],
'dco': ['dco_lfo', 'dco_pwm', 'dco_noise', 'dco_sub', 'stop_16', 'stop_8', 'stop_4',
'pulse', 'saw', 'pwm_manual', 'vca_level', 'vca_gate'],
'dco': ['dco_lfo', 'dco_pwm', 'dco_noise', 'dco_sub',
'stop_16', 'stop_8', 'stop_4',
'pulse', 'saw', 'pwm_manual', 'vca_level', 'vca_gate',
'portamento'],
'vcf': ['vcf_neg', 'vcf_env', 'vcf_freq', 'vcf_lfo', 'vcf_res', 'vcf_kbd'],
'env': ['env_a', 'env_d', 'env_s', 'env_r'],
'cho': ['chorus', 'hpf']}
Expand Down Expand Up @@ -300,6 +303,12 @@ def base_freq(self):
base_freq *= 2
return base_freq

def _portamento_ms(self, port_val):
# Portamento maps exponentially from 1 = 10 ms to 127 = 2560 ms
if port_val == 0:
return 0
return int(round(20 * math.pow(2, port_val * 127 / 30)))

def init_AMY(self):
"""Output AMY commands to set up patches on all the allocated voices.
Send amy.send(osc=0, note=50, vel=1) afterwards."""
Expand Down Expand Up @@ -353,10 +362,12 @@ def update_dco(self):
if self.pwm_manual:
# Swap duty parameters.
const_duty, lfo_duty = lfo_duty, const_duty
port_ms = self._portamento_ms(self.portamento)
self.amy_send(
osc=self.pwm_osc,
amp=self._amp_coef_string(float(self.pulse)),
freq=freq_str,
portamento=port_ms,
duty='%s,,,,,%s' % (
ffmt(0.5 + 0.5 * const_duty), ffmt(0.5 * lfo_duty)
),
Expand All @@ -365,11 +376,13 @@ def update_dco(self):
osc=self.saw_osc,
amp=self._amp_coef_string(float(self.saw)),
freq=freq_str,
portamento=port_ms,
)
self.amy_send(
osc=self.sub_osc,
amp=self._amp_coef_string(float(self.dco_sub)),
freq=self._freq_coef_string(base_freq / 2.0),
portamento=port_ms,
)
self.amy_send(
osc=self.nse_osc,
Expand Down
25 changes: 14 additions & 11 deletions src/amy.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ void clone_osc(uint16_t i, uint16_t f) {
synth[i].eq_h = synth[f].eq_h;
synth[i].logratio = synth[f].logratio;
synth[i].resonance = synth[f].resonance;
synth[i].portamento_ms = synth[f].portamento_ms;
synth[i].portamento_alpha = synth[f].portamento_alpha;
//synth[i].velocity = synth[f].velocity;
//synth[i].step = synth[f].step;
//synth[i].sample = synth[f].sample;
Expand Down Expand Up @@ -675,7 +675,7 @@ void reset_osc(uint16_t i ) {
AMY_UNSET(synth[i].logratio);
synth[i].resonance = 0.7f;
msynth[i].resonance = 0.7f;
synth[i].portamento_ms = 0;
synth[i].portamento_alpha = 0;
synth[i].velocity = 0;
synth[i].step = 0;
synth[i].sample = F2S(0);
Expand Down Expand Up @@ -831,9 +831,9 @@ void show_debug(uint8_t type) {
fprintf(stderr,"global: volume %f bend %f eq: %f %f %f \n", amy_global.volume, amy_global.pitch_bend, S2F(amy_global.eq[0]), S2F(amy_global.eq[1]), S2F(amy_global.eq[2]));
//printf("mod global: filter %f resonance %f\n", mglobal.filter_freq, mglobal.resonance);
for(uint16_t i=0;i<10 /* AMY_OSCS */;i++) {
fprintf(stderr,"osc %d: status %d wave %d mod_source %d velocity %f logratio %f feedback %f filtype %d resonance %f portamento_ms %d step %f chained %d algo %d source %d,%d,%d,%d,%d,%d \n",
fprintf(stderr,"osc %d: status %d wave %d mod_source %d velocity %f logratio %f feedback %f filtype %d resonance %f portamento_alpha %f step %f chained %d algo %d source %d,%d,%d,%d,%d,%d \n",
i, synth[i].status, synth[i].wave, synth[i].mod_source,
synth[i].velocity, synth[i].logratio, synth[i].feedback, synth[i].filter_type, synth[i].resonance, synth[i].portamento_ms, P2F(synth[i].step), synth[i].chained_osc,
synth[i].velocity, synth[i].logratio, synth[i].feedback, synth[i].filter_type, synth[i].resonance, synth[i].portamento_alpha, P2F(synth[i].step), synth[i].chained_osc,
synth[i].algorithm,
synth[i].algo_source[0], synth[i].algo_source[1], synth[i].algo_source[2], synth[i].algo_source[3], synth[i].algo_source[4], synth[i].algo_source[5] );
fprintf(stderr, " amp_coefs: %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n", synth[i].amp_coefs[0], synth[i].amp_coefs[1], synth[i].amp_coefs[2], synth[i].amp_coefs[3], synth[i].amp_coefs[4], synth[i].amp_coefs[5], synth[i].amp_coefs[6]);
Expand Down Expand Up @@ -920,6 +920,10 @@ int chained_osc_would_cause_loop(uint16_t osc, uint16_t chained_osc) {
#define PARAM_IS_COMBO_COEF(param, base) ((param) >= (base) && (param) < (base) + NUM_COMBO_COEFS)
#define PARAM_IS_BP_COEF(param) ((param) >= BP_START && (param) < BP_END)

float portamento_ms_to_alpha(uint16_t portamento_ms) {
return 1.0f - 1.0f / (1 + portamento_ms * AMY_SAMPLE_RATE / 1000 / AMY_BLOCK_SIZE);
}

// play an event, now -- tell the audio loop to start making noise
void play_event(struct delta d) {
AMY_PROFILE_START(PLAY_EVENT)
Expand Down Expand Up @@ -1014,7 +1018,7 @@ void play_event(struct delta d) {
if(d.param == FILTER_TYPE) synth[d.osc].filter_type = *(uint8_t *)&d.data;
if(d.param == RESONANCE) synth[d.osc].resonance = *(float *)&d.data;

if(d.param == PORTAMENTO) synth[d.osc].portamento_ms = *(uint16_t *)&d.data;
if(d.param == PORTAMENTO) synth[d.osc].portamento_alpha = portamento_ms_to_alpha(*(uint16_t *)&d.data);

if(d.param == ALGORITHM) synth[d.osc].algorithm = *(uint8_t *)&d.data;

Expand Down Expand Up @@ -1067,8 +1071,8 @@ void play_event(struct delta d) {
initial_logfreq += synth[d.osc].logfreq_coefs[COEF_NOTE] * logfreq_for_midi_note(synth[d.osc].midi_note);
}
// If we're coming out of note-off, set the freq history for portamento.
if (AMY_IS_SET(synth[d.osc].note_off_clock))
msynth[d.osc].last_logfreq = initial_logfreq;
//if (AMY_IS_SET(synth[d.osc].note_off_clock))
// msynth[d.osc].last_logfreq = initial_logfreq;
// Now we've tested that, we can reset note-off clocks.
AMY_UNSET(synth[d.osc].note_off_clock); // Most recent note event is not note-off.
AMY_UNSET(synth[d.osc].zero_amp_clock);
Expand Down Expand Up @@ -1164,11 +1168,10 @@ void hold_and_modify(uint16_t osc) {

// copy all the modifier variables
float logfreq = combine_controls(ctrl_inputs, synth[osc].logfreq_coefs);
if (synth[osc].portamento_ms > 0) {
float portamento_alpha = 1.0f / (1 + synth[osc].portamento_ms * AMY_SAMPLE_RATE / 1000 / AMY_BLOCK_SIZE);
msynth[osc].logfreq = msynth[osc].last_logfreq + portamento_alpha * (logfreq - msynth[osc].last_logfreq);
} else {
if (synth[osc].portamento_alpha == 0) {
msynth[osc].logfreq = logfreq;
} else {
msynth[osc].logfreq = logfreq + synth[osc].portamento_alpha * (msynth[osc].last_logfreq - logfreq);
}
msynth[osc].last_logfreq = msynth[osc].logfreq;
float filter_logfreq = combine_controls(ctrl_inputs, synth[osc].filter_logfreq_coefs);
Expand Down
2 changes: 1 addition & 1 deletion src/amy.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ struct synthinfo {
float volume;
float logratio;
float resonance;
uint16_t portamento_ms;
float portamento_alpha;
uint16_t chained_osc;
uint16_t mod_source;
uint8_t algorithm;
Expand Down
Loading

0 comments on commit 638d07b

Please sign in to comment.