commit 59315edbe05268fdf38279eb8470f2f1a1ab0d29
parent d08bbf38af2da1284a7dc97dbfc058b5949533f6
Author: Hans Petter Selasky <hps@selasky.org>
Date: Mon, 4 Feb 2019 10:13:03 +0100
Add basic support for floating point notes.
Signed-off-by: Hans Petter Selasky <hps@selasky.org>
Diffstat:
22 files changed, 73 insertions(+), 63 deletions(-)
diff --git a/src/Containers/NotePool.cpp b/src/Containers/NotePool.cpp
@@ -193,10 +193,10 @@ void NotePool::insertLegatoNote(note_t note, uint8_t sendto, SynthDescriptor des
};
//There should only be one pair of notes which are still playing
-void NotePool::applyLegato(LegatoParams &par)
+void NotePool::applyLegato(note_t note, LegatoParams &par)
{
for(auto &desc:activeDesc()) {
- desc.note = par.midinote;
+ desc.note = note;
for(auto &synth:activeNotes(desc))
try {
synth.note->legatonote(par);
diff --git a/src/Containers/NotePool.h b/src/Containers/NotePool.h
@@ -122,7 +122,7 @@ class NotePool
void insertLegatoNote(note_t note, uint8_t sendto, SynthDescriptor desc);
void upgradeToLegato(void);
- void applyLegato(LegatoParams &par);
+ void applyLegato(note_t note, LegatoParams &par);
void makeUnsustainable(note_t note);
diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp
@@ -879,14 +879,14 @@ void Master::defaults()
/*
* Note On Messages (velocity=0 for NoteOff)
*/
-void Master::noteOn(char chan, note_t note, char velocity)
+void Master::noteOn(char chan, note_t note, char velocity, float note_log2_freq)
{
if(velocity) {
for(int npart = 0; npart < NUM_MIDI_PARTS; ++npart) {
if(chan == part[npart]->Prcvchn) {
fakepeakpart[npart] = velocity * 2;
if(part[npart]->Penabled)
- part[npart]->NoteOn(note, velocity, keyshift);
+ part[npart]->NoteOn(note, velocity, keyshift, note_log2_freq);
}
}
activeNotes[note] = 1;
diff --git a/src/Misc/Master.h b/src/Misc/Master.h
@@ -104,7 +104,10 @@ class Master
void putalldata(const char *data);
//Midi IN
- void noteOn(char chan, note_t note, char velocity);
+ void noteOn(char chan, note_t note, char velocity) {
+ noteOn(chan, note, velocity, note / 12.0f);
+ };
+ void noteOn(char chan, note_t note, char velocity, float note_log2_freq);
void noteOff(char chan, note_t note);
void polyphonicAftertouch(char chan, note_t note, char velocity);
void setController(char chan, int type, int par);
diff --git a/src/Misc/Microtonal.cpp b/src/Misc/Microtonal.cpp
@@ -257,8 +257,10 @@ unsigned char Microtonal::getoctavesize() const
/*
* Get the frequency according the note number
*/
-float Microtonal::getnotefreq(note_t note, int keyshift) const
+float Microtonal::getnotefreq(float note_log2_freq, int keyshift) const
{
+ note_t note = roundf(12.0f * note_log2_freq);
+
// in this function will appears many times things like this:
// var=(a+b*100)%b
// I had written this way because if I use var=a%b gives unwanted results when a<0
@@ -272,9 +274,8 @@ float Microtonal::getnotefreq(note_t note, int keyshift) const
powf(2.0f, (Pglobalfinedetune - 64.0f) / 1200.0f); //-64.0f .. 63.0f cents
if(Penabled == 0) //12tET
- return powf(2.0f,
- (note - PAnote
- + keyshift) / 12.0f) * PAfreq * globalfinedetunerap;
+ return powf(2.0f, note_log2_freq +
+ ((keyshift - PAnote) / 12.0f)) * PAfreq * globalfinedetunerap;
int scaleshift =
((int)Pscaleshift - 64 + (int) octavesize * 100) % octavesize;
diff --git a/src/Misc/Microtonal.h b/src/Misc/Microtonal.h
@@ -68,7 +68,7 @@ class Microtonal
void defaults();
/**Calculates the frequency for a given note
*/
- float getnotefreq(note_t note, int keyshift) const;
+ float getnotefreq(float note_log2_freq, int keyshift) const;
//Parameters
diff --git a/src/Misc/Part.cpp b/src/Misc/Part.cpp
@@ -275,7 +275,7 @@ Part::Part(Allocator &alloc, const SYNTH_T &synth_, const AbsTime &time_,
Pname = new char[PART_MAX_NAME_LEN];
oldvolumel = oldvolumer = 0.5f;
- lastnote = -1;
+ lastnote = -1;
defaults();
assert(partefx[0]);
@@ -452,7 +452,8 @@ static int kit_usage(const Part::Kit *kits, int note, int mode)
*/
bool Part::NoteOn(note_t note,
unsigned char velocity,
- int masterkeyshift)
+ int masterkeyshift,
+ float note_log2_freq)
{
//Verify Basic Mode and sanity
const bool isRunningNote = notePool.existsRunningNote();
@@ -471,6 +472,7 @@ bool Part::NoteOn(note_t note,
monomemPush(note);
monomem[note].velocity = velocity;
monomem[note].mkeyshift = masterkeyshift;
+ monomem[note].note_log2_freq = note_log2_freq;
} else if(!monomemEmpty())
monomemClear();
@@ -485,9 +487,9 @@ bool Part::NoteOn(note_t note,
const float vel = getVelocity(velocity, Pvelsns, Pveloffs);
const int partkeyshift = (int)Pkeyshift - 64;
const int keyshift = masterkeyshift + partkeyshift;
- const float notebasefreq = getBaseFreq(note, keyshift);
+ const float notebasefreq = getBaseFreq(note_log2_freq, keyshift);
- if(notebasefreq < 0)
+ if(notebasefreq < 0.0f)
return false;
//Portamento
@@ -507,8 +509,8 @@ bool Part::NoteOn(note_t note,
//Adjust Existing Notes
if(doingLegato) {
- LegatoParams pars = {notebasefreq, vel, portamento, note, true, prng()};
- notePool.applyLegato(pars);
+ LegatoParams pars = {notebasefreq, vel, portamento, note_log2_freq, true, prng()};
+ notePool.applyLegato(note, pars);
return true;
}
@@ -523,7 +525,7 @@ bool Part::NoteOn(note_t note,
continue;
SynthParams pars{memory, ctl, synth, time, notebasefreq, vel,
- portamento, note, false, prng()};
+ portamento, note_log2_freq, false, prng()};
const int sendto = Pkitmode ? item.sendto() : 0;
try {
@@ -729,16 +731,18 @@ void Part::MonoMemRenote()
{
note_t mmrtempnote = monomemBack(); // Last list element.
monomemPop(mmrtempnote); // We remove it, will be added again in NoteOn(...).
- NoteOn(mmrtempnote, monomem[mmrtempnote].velocity,
- monomem[mmrtempnote].mkeyshift);
+ NoteOn(mmrtempnote,
+ monomem[mmrtempnote].velocity,
+ monomem[mmrtempnote].mkeyshift,
+ monomem[mmrtempnote].note_log2_freq);
}
-float Part::getBaseFreq(note_t note, int keyshift) const
+float Part::getBaseFreq(float note_log2_freq, int keyshift) const
{
if(Pdrummode)
- return 440.0f * powf(2.0f, (note - 69.0f) / 12.0f);
+ return 440.0f * powf(2.0f, note_log2_freq - (69.0f / 12.0f));
else
- return microtonal->getnotefreq(note, keyshift);
+ return microtonal->getnotefreq(note_log2_freq, keyshift);
}
float Part::getVelocity(uint8_t velocity, uint8_t velocity_sense,
diff --git a/src/Misc/Part.h b/src/Misc/Part.h
@@ -43,9 +43,13 @@ class Part
// Midi commands implemented
//returns true when note is successfully applied
+ bool NoteOn(note_t note, uint8_t vel, int shift) REALTIME {
+ return (NoteOn(note, vel, shift, note / 12.0f));
+ };
bool NoteOn(note_t note,
unsigned char velocity,
- int masterkeyshift) REALTIME;
+ int masterkeyshift,
+ float note_log2_freq) REALTIME;
void NoteOff(note_t note) REALTIME;
void PolyphonicAftertouch(note_t note,
unsigned char velocity,
@@ -159,7 +163,7 @@ class Part
private:
void MonoMemRenote(); // MonoMem stuff.
- float getBaseFreq(note_t note, int keyshift) const;
+ float getBaseFreq(float note_log2_freq, int keyshift) const;
float getVelocity(uint8_t velocity, uint8_t velocity_sense,
uint8_t velocity_offset) const;
void verifyKeyMode(void);
@@ -187,6 +191,7 @@ class Part
struct {
unsigned char velocity;
int mkeyshift; // I'm not sure masterkeyshift should be remembered.
+ float note_log2_freq;
} monomem[256];
/* 256 is to cover all possible note values.
monomem[] is used in conjunction with the list to
diff --git a/src/Synth/ADnote.cpp b/src/Synth/ADnote.cpp
@@ -42,7 +42,7 @@ ADnote::ADnote(ADnoteParameters *pars_, SynthParams &spars,
ADnoteParameters &pars = *pars_;
portamento = spars.portamento;
- midinote = spars.note;
+ note_log2_freq = spars.note_log2_freq;
NoteEnabled = ON;
basefreq = spars.frequency;
velocity = spars.velocity;
@@ -512,7 +512,7 @@ void ADnote::setupVoiceMod(int nvoice, bool first_run)
SynthNote *ADnote::cloneLegato(void)
{
SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
- (bool)portamento, legato.param.midinote, true,
+ (bool)portamento, legato.param.note_log2_freq, true,
initial_seed };
return memory.alloc<ADnote>(&pars, sp);
}
@@ -529,7 +529,7 @@ void ADnote::legatonote(LegatoParams lpars)
return;
portamento = lpars.portamento;
- midinote = lpars.midinote;
+ note_log2_freq = lpars.note_log2_freq;
basefreq = lpars.frequency;
initial_seed = lpars.seed;
current_prng_state = lpars.seed;
@@ -1071,9 +1071,7 @@ float ADnote::getvoicebasefreq(int nvoice) const
float fixedfreq = 440.0f;
int fixedfreqET = NoteVoicePar[nvoice].fixedfreqET;
if(fixedfreqET != 0) { //if the frequency varies according the keyboard note
- float tmp =
- (midinote
- - 69.0f) / 12.0f
+ float tmp = (note_log2_freq - (69.0f / 12.0f))
* (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f);
if(fixedfreqET <= 64)
fixedfreq *= powf(2.0f, tmp);
diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h
@@ -110,7 +110,7 @@ class ADnote:public SynthNote
//GLOBALS
ADnoteParameters &pars;
unsigned char stereo; //if the note is stereo (allows note Panning)
- note_t midinote;
+ float note_log2_freq;
float velocity, basefreq;
ONOFFTYPE NoteEnabled;
diff --git a/src/Synth/PADnote.cpp b/src/Synth/PADnote.cpp
@@ -35,13 +35,13 @@ PADnote::PADnote(const PADnoteParameters *parameters,
NoteGlobalPar.FilterLfo = nullptr;
firsttime = true;
- setup(pars.frequency, pars.velocity, pars.portamento, pars.note, false, wm, prefix);
+ setup(pars.frequency, pars.velocity, pars.portamento, pars.note_log2_freq, false, wm, prefix);
}
void PADnote::setup(float freq,
float velocity_,
int portamento_,
- note_t midinote,
+ float note_log2_freq,
bool legato,
WatchManager *wm,
const char *prefix)
@@ -58,8 +58,7 @@ void PADnote::setup(float freq,
int fixedfreqET = pars.PfixedfreqET;
if(fixedfreqET != 0) { //if the frequency varies according the keyboard note
float tmp =
- (midinote
- - 69.0f) / 12.0f
+ (note_log2_freq - (69.0f / 12.0f))
* (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f);
if(fixedfreqET <= 64)
basefreq *= powf(2.0f, tmp);
@@ -198,7 +197,7 @@ void PADnote::setup(float freq,
SynthNote *PADnote::cloneLegato(void)
{
SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
- (bool)portamento, legato.param.midinote, true, legato.param.seed};
+ (bool)portamento, legato.param.note_log2_freq, true, legato.param.seed};
return memory.alloc<PADnote>(&pars, sp, interpolation);
}
@@ -208,7 +207,7 @@ void PADnote::legatonote(LegatoParams pars)
if(legato.update(pars))
return;
- setup(pars.frequency, pars.velocity, pars.portamento, pars.midinote, true);
+ setup(pars.frequency, pars.velocity, pars.portamento, pars.note_log2_freq, true);
}
diff --git a/src/Synth/PADnote.h b/src/Synth/PADnote.h
@@ -38,7 +38,7 @@ class PADnote:public SynthNote
void releasekey();
private:
void setup(float freq, float velocity, int portamento_,
- note_t midinote, bool legato = false, WatchManager *wm=0, const char *prefix=0);
+ float note_log2_freq, bool legato = false, WatchManager *wm=0, const char *prefix=0);
void fadein(float *smps);
void computecurrentparameters();
bool finished_;
diff --git a/src/Synth/SUBnote.cpp b/src/Synth/SUBnote.cpp
@@ -46,7 +46,7 @@ SUBnote::SUBnote(const SUBnoteParameters *parameters, SynthParams &spars, WatchM
NoteEnabled(true),
lfilter(nullptr), rfilter(nullptr)
{
- setup(spars.frequency, spars.velocity, spars.portamento, spars.note, false, wm, prefix);
+ setup(spars.frequency, spars.velocity, spars.portamento, spars.note_log2_freq, false, wm, prefix);
}
float SUBnote::setupFilters(int *pos, bool automation)
@@ -91,7 +91,7 @@ float SUBnote::setupFilters(int *pos, bool automation)
void SUBnote::setup(float freq,
float velocity,
int portamento_,
- note_t midinote,
+ float note_log2_freq,
bool legato,
WatchManager *wm,
const char *prefix)
@@ -120,7 +120,7 @@ void SUBnote::setup(float freq,
basefreq = 440.0f;
int fixedfreqET = pars.PfixedfreqET;
if(fixedfreqET) { //if the frequency varies according the keyboard note
- float tmp = (midinote - 69.0f) / 12.0f
+ float tmp = (note_log2_freq - (69.0f / 12.0f))
* (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f);
if(fixedfreqET <= 64)
basefreq *= powf(2.0f, tmp);
@@ -197,7 +197,7 @@ void SUBnote::setup(float freq,
SynthNote *SUBnote::cloneLegato(void)
{
SynthParams sp{memory, ctl, synth, time, legato.param.freq, velocity,
- portamento, legato.param.midinote, true, legato.param.seed};
+ portamento, legato.param.note_log2_freq, true, legato.param.seed};
return memory.alloc<SUBnote>(&pars, sp);
}
@@ -208,7 +208,7 @@ void SUBnote::legatonote(LegatoParams pars)
return;
try {
- setup(pars.frequency, pars.velocity, pars.portamento, pars.midinote,
+ setup(pars.frequency, pars.velocity, pars.portamento, pars.note_log2_freq,
true, wm);
} catch (std::bad_alloc &ba) {
std::cerr << "failed to set legato note parameter in SUBnote: " << ba.what() << std::endl;
diff --git a/src/Synth/SUBnote.h b/src/Synth/SUBnote.h
@@ -38,7 +38,7 @@ class SUBnote:public SynthNote
void setup(float freq,
float velocity,
int portamento_,
- note_t midinote,
+ float note_log2_freq,
bool legato = false, WatchManager *wm = 0, const char *prefix = 0);
float setupFilters(int *pos, bool automation);
void computecurrentparameters();
diff --git a/src/Synth/SynthNote.cpp b/src/Synth/SynthNote.cpp
@@ -21,11 +21,11 @@ namespace zyn {
SynthNote::SynthNote(SynthParams &pars)
:memory(pars.memory),
legato(pars.synth, pars.frequency, pars.velocity, pars.portamento,
- pars.note, pars.quiet, pars.seed), ctl(pars.ctl), synth(pars.synth), time(pars.time)
+ pars.note_log2_freq, pars.quiet, pars.seed), ctl(pars.ctl), synth(pars.synth), time(pars.time)
{}
SynthNote::Legato::Legato(const SYNTH_T &synth_, float freq, float vel, int port,
- note_t note, bool quiet, prng_t seed)
+ float note_log2_freq, bool quiet, prng_t seed)
:synth(synth_)
{
// Initialise some legato-specific vars
@@ -38,7 +38,7 @@ SynthNote::Legato::Legato(const SYNTH_T &synth_, float freq, float vel, int port
param.freq = freq;
param.vel = vel;
param.portamento = port;
- param.midinote = note;
+ param.note_log2_freq = note_log2_freq;
param.seed = seed;
lastfreq = 0.0f;
silent = quiet;
@@ -53,7 +53,7 @@ int SynthNote::Legato::update(LegatoParams pars)
param.freq = pars.frequency;
param.vel = pars.velocity;
param.portamento = pars.portamento;
- param.midinote = pars.midinote;
+ param.note_log2_freq = pars.note_log2_freq;
if(msg == LM_Norm) {
if(silent) {
fade.m = 0.0f;
@@ -92,7 +92,7 @@ void SynthNote::Legato::apply(SynthNote ¬e, float *outl, float *outr)
decounter = -10;
msg = LM_ToNorm;
LegatoParams pars{param.freq, param.vel, param.portamento,
- param.midinote, false, param.seed};
+ param.note_log2_freq, false, param.seed};
note.legatonote(pars);
break;
}
@@ -134,7 +134,7 @@ void SynthNote::Legato::apply(SynthNote ¬e, float *outl, float *outr)
//previous freq during the fadeout.
float catchupfreq = param.freq * (param.freq / lastfreq);
LegatoParams pars{catchupfreq, param.vel, param.portamento,
- param.midinote, false, param.seed};
+ param.note_log2_freq, false, param.seed};
note.legatonote(pars);
break;
}
@@ -154,7 +154,7 @@ void SynthNote::Legato::apply(SynthNote ¬e, float *outl, float *outr)
void SynthNote::setVelocity(float velocity_) {
legato.setSilent(true); //Let legato.update(...) returns 0.
LegatoParams pars{legato.getFreq(), velocity_,
- legato.getPortamento(), legato.getMidiNote(), true, legato.getSeed()};
+ legato.getPortamento(), legato.getNoteLog2Freq(), true, legato.getSeed()};
try {
legatonote(pars);
} catch (std::bad_alloc &ba) {
diff --git a/src/Synth/SynthNote.h b/src/Synth/SynthNote.h
@@ -29,7 +29,7 @@ struct SynthParams
float frequency; //Note base frequency
float velocity; //Velocity of the Note
bool portamento;//True if portamento is used for this note
- note_t note; //Integer value of the note
+ float note_log2_freq; //Floating point value of the note
bool quiet; //Initial output condition for legato notes
prng_t seed; //Random seed
};
@@ -39,7 +39,7 @@ struct LegatoParams
float frequency;
float velocity;
bool portamento;
- note_t midinote;
+ float note_log2_freq; //Floating point value of the note
bool externcall;
prng_t seed;
};
@@ -84,7 +84,7 @@ class SynthNote
{
public:
Legato(const SYNTH_T &synth_, float freq, float vel, int port,
- note_t note, bool quiet, prng_t seed);
+ float note_log2_freq, bool quiet, prng_t seed);
void apply(SynthNote ¬e, float *outl, float *outr);
int update(LegatoParams pars);
@@ -102,7 +102,7 @@ class SynthNote
struct { // Note parameters
float freq, vel;
bool portamento;
- note_t midinote;
+ float note_log2_freq;
prng_t seed;
} param;
const SYNTH_T &synth;
@@ -111,7 +111,7 @@ class SynthNote
float getFreq() {return param.freq; }
float getVelocity() {return param.vel; }
bool getPortamento() {return param.portamento; }
- note_t getMidiNote() {return param.midinote; }
+ float getNoteLog2Freq() {return param.note_log2_freq; }
prng_t getSeed() {return param.seed;}
void setSilent(bool silent_) {silent = silent_; }
void setDecounter(int decounter_) {decounter = decounter_; }
diff --git a/src/Tests/AdNoteTest.h b/src/Tests/AdNoteTest.h
@@ -91,7 +91,7 @@ class AdNoteTest:public CxxTest::TestSuite
//lets go with.... 50! as a nice note
testnote = 50;
float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f);
- SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote, false, prng()};
+ SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote / 12.0f, false, prng()};
note = new ADnote(defaultPreset, pars);
diff --git a/src/Tests/MemoryStressTest.h b/src/Tests/MemoryStressTest.h
@@ -86,7 +86,7 @@ class AdNoteTest:public CxxTest::TestSuite
unsigned char testnote = 42;
float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f);
- SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote, false, prng()};
+ SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote / 12.0f, false, prng()};
std::vector<ADnote*> notes;
diff --git a/src/Tests/MicrotonalTest.h b/src/Tests/MicrotonalTest.h
@@ -62,7 +62,7 @@ class MicrotonalTest:public CxxTest::TestSuite
for(int i = 0; i < 128; ++i)
TS_ASSERT_EQUALS(testMicro->Pmapping[i], i);
- TS_ASSERT_DELTA(testMicro->getnotefreq(19, 0), 24.4997f, 0.0001f);
+ TS_ASSERT_DELTA(testMicro->getnotefreq(19 / 12.0f, 0), 24.4997f, 0.0001f);
}
//Tests saving/loading to XML
diff --git a/src/Tests/PadNoteTest.h b/src/Tests/PadNoteTest.h
@@ -104,7 +104,7 @@ class PadNoteTest:public CxxTest::TestSuite
//lets go with.... 50! as a nice note
testnote = 50;
float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f);
- SynthParams pars_{memory, *controller, *synth, *time, freq, 120, 0, testnote, false, prng()};
+ SynthParams pars_{memory, *controller, *synth, *time, freq, 120, 0, testnote / 12.0f, false, prng()};
note = new PADnote(pars, pars_, interpolation);
}
diff --git a/src/Tests/SubNoteTest.h b/src/Tests/SubNoteTest.h
@@ -78,7 +78,7 @@ class SubNoteTest:public CxxTest::TestSuite
testnote = 50;
float freq = 440.0f * powf(2.0f, (testnote - 69.0f) / 12.0f);
- SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote, false, prng()};
+ SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote / 12.0f, false, prng()};
note = new SUBnote(defaultPreset, pars);
this->pars = defaultPreset;
}
diff --git a/src/Tests/UnisonTest.h b/src/Tests/UnisonTest.h
@@ -98,7 +98,7 @@ class AdNoteTest:public CxxTest::TestSuite
params->VoicePar[0].Unison_vibratto_speed = e;
params->VoicePar[0].Unison_invert_phase = f;
- SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote, false, prng()};
+ SynthParams pars{memory, *controller, *synth, *time, freq, 120, 0, testnote / 12.0f, false, prng()};
note = new ADnote(params, pars);
note->noteout(outL, outR);
TS_ASSERT_DELTA(outL[80], values[0], 1e-5);