diff --git a/cpp/src/dx7note.cc b/cpp/src/dx7note.cc index 9e775a7..bddab1e 100644 --- a/cpp/src/dx7note.cc +++ b/cpp/src/dx7note.cc @@ -50,11 +50,13 @@ int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) { // (1 << 24) / log(2) logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5); } - // TODO: detune + // This was measured at 7.213Hz per count at 9600Hz, but the exact + // value is somewhat dependent on midinote. Close enough for now. + logfreq += 12606 * (detune - 7); } else { // ((1 << 24) * log(10) / log(2) * .01) << 3 - logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; - // TODO: detune + logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; + logfreq += detune > 7 ? 13457 * (detune - 7) : 0; } int32_t base_freq = Freqlut::lookup(logfreq); return base_freq; @@ -122,8 +124,7 @@ int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth, } } -// Considering making this an init method... -Dx7Note::Dx7Note(const char bulk[128], int midinote, int velocity) { +void Dx7Note::init(const char bulk[128], int midinote, int velocity) { char patch[156]; UnpackPatch(bulk, patch); // TODO: move this out, take unpacked patch for (int op = 0; op < 6; op++) { @@ -135,6 +136,7 @@ Dx7Note::Dx7Note(const char bulk[128], int midinote, int velocity) { levels[i] = patch[off + 4 + i]; } int outlevel = patch[off + 16]; + outlevel = Env::scaleoutlevel(outlevel); #ifdef VERBOSE for (int j = 8; j < 12; j++) { cout << (int)patch[off + j] << " "; @@ -143,7 +145,7 @@ Dx7Note::Dx7Note(const char bulk[128], int midinote, int velocity) { int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9], patch[off + 10], patch[off + 11], patch[off + 12]); outlevel += level_scaling; - outlevel = min(99, outlevel); + outlevel = min(127, outlevel); #ifdef VERBOSE cout << op << ": " << level_scaling << " " << outlevel << endl; #endif diff --git a/cpp/src/dx7note.h b/cpp/src/dx7note.h index 34bb00b..da0bb1d 100644 --- a/cpp/src/dx7note.h +++ b/cpp/src/dx7note.h @@ -31,7 +31,7 @@ class Dx7Note { // Interesting question: should the setup be in the constructor, or should // there be an init method? The latter would make it easier to use a fixed // pool of note objects. - Dx7Note(const char patch[128], int midinote, int velocity); + void init(const char patch[128], int midinote, int velocity); // Note: this _adds_ to the buffer. Interesting question whether it's // worth it... diff --git a/cpp/src/env.cc b/cpp/src/env.cc index 65b736c..cb9e335 100644 --- a/cpp/src/env.cc +++ b/cpp/src/env.cc @@ -73,16 +73,19 @@ void Env::setparam(int param, int value) { } const int levellut[] = { - 0, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 + 0, 5, 9, 13, 17, 20, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 42, 43, 45, 46 }; +int Env::scaleoutlevel(int outlevel) { + return outlevel >= 20 ? 28 + outlevel : levellut[outlevel]; +} + void Env::advance(int newix) { ix_ = newix; if (ix_ < 4) { int newlevel = levels_[ix_]; - int actuallevel = newlevel >= 19 ? - 14 + (newlevel >> 1) : levellut[newlevel]; - actuallevel = (actuallevel << 6) + outlevel_ - 3360; + int actuallevel = scaleoutlevel(newlevel) >> 1; + actuallevel = (actuallevel << 6) + outlevel_ - 4256; actuallevel = actuallevel < 16 ? 16 : actuallevel; // level here is same as Java impl targetlevel_ = actuallevel << 16; diff --git a/cpp/src/env.h b/cpp/src/env.h index 20e2d5c..d76dc06 100644 --- a/cpp/src/env.h +++ b/cpp/src/env.h @@ -39,6 +39,7 @@ class Env { void keydown(bool down); void setparam(int param, int value); + static int scaleoutlevel(int outlevel); private: int rates_[4]; int levels_[4]; diff --git a/cpp/src/fm_core.cc b/cpp/src/fm_core.cc index a6ebe1d..3c95cb0 100644 --- a/cpp/src/fm_core.cc +++ b/cpp/src/fm_core.cc @@ -109,6 +109,7 @@ void FmCore::dump() { void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift) { + const int kLevelThresh = 1120; const FmAlgorithm alg = algorithms[algorithm]; bool has_contents[3] = { true, false, false }; for (int op = 0; op < 6; op++) { @@ -120,7 +121,7 @@ void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm, int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); int32_t gain1 = param.gain[0]; int32_t gain2 = param.gain[1]; - if (gain1 != 0 || gain2 != 0) { + if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { if (!has_contents[outbus]) { add = false; } diff --git a/cpp/src/synth_unit.cc b/cpp/src/synth_unit.cc index f024d0a..946150c 100644 --- a/cpp/src/synth_unit.cc +++ b/cpp/src/synth_unit.cc @@ -44,9 +44,10 @@ char epiano[] = { SynthUnit::SynthUnit(RingBuffer *ring_buffer) { ring_buffer_ = ring_buffer; for (int note = 0; note < max_active_notes; ++note) { - active_note_[note].dx7_note = NULL; + active_note_[note].dx7_note = new Dx7Note; active_note_[note].keydown = false; active_note_[note].sustained = false; + active_note_[note].live = false; } input_buffer_index_ = 0; memcpy(patch_data_, epiano, sizeof(epiano)); @@ -117,13 +118,13 @@ int SynthUnit::ProcessMidiMessage(const uint8_t *buf, int buf_size) { // note on int note_ix = AllocateNote(); if (note_ix >= 0) { - delete active_note_[note_ix].dx7_note; active_note_[note_ix].midi_note = buf[1]; active_note_[note_ix].keydown = true; active_note_[note_ix].sustained = sustain_; + active_note_[note_ix].live = true; const uint8_t *patch = patch_data_ + 128 * current_patch_; - active_note_[note_ix].dx7_note = - new Dx7Note((const char *)patch, buf[1], buf[2]); + active_note_[note_ix].dx7_note->init( + (const char *)patch, buf[1], buf[2]); } return 3; } @@ -218,7 +219,7 @@ void SynthUnit::GetSamples(int n_samples, int16_t *buffer) { audiobuf.get()[j] = 0; } for (int note = 0; note < max_active_notes; ++note) { - if (active_note_[note].dx7_note != NULL) { + if (active_note_[note].live) { active_note_[note].dx7_note->compute(audiobuf.get()); } } diff --git a/cpp/src/synth_unit.h b/cpp/src/synth_unit.h index 31cea4f..a484000 100644 --- a/cpp/src/synth_unit.h +++ b/cpp/src/synth_unit.h @@ -22,6 +22,7 @@ struct ActiveNote { int midi_note; bool keydown; bool sustained; + bool live; Dx7Note *dx7_note; };