-
Notifications
You must be signed in to change notification settings - Fork 525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add essentiamath #1417
Add essentiamath #1417
Changes from 17 commits
e7544ae
0813303
9bbc41d
905fd16
4b061bf
b426754
2191b6d
be9d709
9f8cb11
4c522f9
323cc44
3340cc9
c10dc6b
c84a9a5
a06268a
c50c337
ed89c21
4d2acbe
5575528
5dc2414
1e09fd7
9b383ab
1e6b692
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -738,8 +738,88 @@ inline Real hz2hz(Real hz){ | |
return hz; | ||
} | ||
|
||
inline Real hz2cents(Real hz) { | ||
return 12 * std::log(hz/440)/std::log(2.) + 69; | ||
inline Real cents2hz(Real frequencyB, Real cents) { | ||
return frequencyB * powf(2.0, cents / 1200.0); | ||
} | ||
|
||
inline Real hz2cents(Real frequencyA, Real frequencyB) { | ||
return 1200 * log2(frequencyA / frequencyB); | ||
} | ||
|
||
inline int hz2midi(Real hz, Real tuningFrequency) { | ||
return 69 + (int) round(log2(hz / tuningFrequency) * 12); | ||
} | ||
|
||
inline Real midi2hz(int midiNoteNumber, Real tuningFrequency) { | ||
return tuningFrequency * powf(2, (midiNoteNumber - 69) / 12.0); | ||
} | ||
|
||
inline std::string note2root(std::string note) { | ||
return note.substr(0, note.size()-1); | ||
} | ||
|
||
inline int note2octave(std::string note) { | ||
char octaveChar = note.back(); | ||
return octaveChar - '0'; | ||
} | ||
|
||
inline std::string midi2note(int midiNoteNumber) { | ||
const std::vector<std::string> ALL_NOTES { "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#" }; | ||
int nNotes = ALL_NOTES.size(); | ||
int CIdx = 3; | ||
int diffCIdx = nNotes - CIdx; | ||
int noteIdx = midiNoteNumber - 69; | ||
int idx = abs(noteIdx) % nNotes; | ||
int octave = (CIdx + 1) + floor((noteIdx + diffCIdx) / nNotes); | ||
if (noteIdx < 0) { | ||
idx = abs(idx - nNotes) % nNotes; | ||
} | ||
std::string closest_note = ALL_NOTES[idx] + std::to_string(octave); | ||
return closest_note; | ||
} | ||
|
||
inline int note2midi(std::string note) { | ||
const std::vector<std::string> ALL_NOTES { "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#" }; | ||
int octave = note2octave(note); | ||
std::string root = note2root(note); | ||
int nNotes = ALL_NOTES.size(); | ||
int CIdx = 3; | ||
|
||
int noteIdx = floor((octave - (CIdx + 1)) * nNotes); | ||
int idx = 0; | ||
for (int i = 0; i < nNotes; i++) { | ||
if (ALL_NOTES[i] == root) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Break out of the loop once the matching note is found. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. L796 is doing it by index. However it can be replaced by a |
||
idx = i; | ||
if (idx >= CIdx) { | ||
idx = idx - nNotes; | ||
} | ||
i = nNotes; | ||
} | ||
} | ||
int midiNote = noteIdx + 69 + idx; | ||
return midiNote; | ||
} | ||
|
||
inline std::string hz2note(Real hz, Real tuningFrequency) { | ||
int midiNoteNumber = hz2midi(hz, tuningFrequency); | ||
return midi2note(midiNoteNumber); | ||
} | ||
|
||
inline int note2hz(std::string note, Real tuningFrequency) { | ||
int midiNoteNumber = note2midi(note); | ||
return midi2hz(midiNoteNumber, tuningFrequency); | ||
} | ||
|
||
inline int db2velocity (Real decibels, Real hearingThreshold) { | ||
int velocity = 0; | ||
if (decibels > hearingThreshold) { | ||
velocity = (int)((hearingThreshold - decibels) * 127 / hearingThreshold); // decibels should be negative | ||
} | ||
return velocity; | ||
} | ||
|
||
inline Real velocity2db(int velocity, Real hearingThreshold) { | ||
return -(hearingThreshold * velocity / 127 -hearingThreshold); | ||
} | ||
|
||
inline int argmin(const std::vector<Real>& input) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -389,6 +389,167 @@ hzToMel(PyObject* notUsed, PyObject* arg) { | |
return PyFloat_FromDouble( double(mel) ); | ||
} | ||
|
||
static PyObject* | ||
midiToHz(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
if (argsV.size() != 2 || | ||
(!PyLong_Check(argsV[0]) || !PyFloat_Check(argsV[1]))) { | ||
PyErr_SetString(PyExc_ValueError, "expecting arguments (int midiNoteNumber, Real tuningFrequency)"); | ||
return NULL; | ||
} | ||
Real hz = midi2hz( long( PyLong_AsLong(argsV[0]) ), Real( PyFloat_AS_DOUBLE(argsV[1])) ); | ||
return PyFloat_FromDouble( double(hz) ); | ||
} | ||
|
||
static PyObject* | ||
hzToMidi(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
if (argsV.size() != 2 || | ||
(!PyFloat_Check(argsV[0]) || !PyFloat_Check(argsV[1]))) { | ||
PyErr_SetString(PyExc_ValueError, "expecting arguments (Real hertz, Real tuningFrequency)"); | ||
return NULL; | ||
} | ||
|
||
int midi = hz2midi( Real( PyFloat_AS_DOUBLE(argsV[0]) ), Real( PyFloat_AS_DOUBLE(argsV[1])) ); | ||
return PyLong_FromLong( int(midi) ); | ||
} | ||
|
||
static PyObject* | ||
hzToCents(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
|
||
if (argsV.size() != 2 || !PyFloat_Check(argsV[0]) || !PyFloat_Check(argsV[1])) { | ||
PyErr_SetString(PyExc_TypeError, (char*)"expecting arguments (Real frequencyA, Real frequencyB)"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also here |
||
return NULL; | ||
} | ||
|
||
int cents = hz2cents( Real( PyFloat_AS_DOUBLE(argsV[0]) ), Real( PyFloat_AS_DOUBLE(argsV[1]) ) ); | ||
return PyFloat_FromDouble( int(cents) ); | ||
} | ||
|
||
static PyObject* | ||
centsToHz(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
|
||
if (argsV.size() != 2 || !PyFloat_Check(argsV[0]) || !PyFloat_Check(argsV[1])) { | ||
PyErr_SetString(PyExc_TypeError, (char*)"expecting arguments (Real frequencyB, Real cents)"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and here |
||
return NULL; | ||
} | ||
|
||
Real hz = cents2hz( Real( PyFloat_AS_DOUBLE(argsV[0]) ), Real( PyFloat_AS_DOUBLE(argsV[1]) ) ); | ||
return PyFloat_FromDouble( hz ); | ||
} | ||
|
||
static PyObject* | ||
midiToNote(PyObject* notUsed, PyObject* arg) { | ||
|
||
if (!PyLong_Check(arg)) { | ||
PyErr_SetString(PyExc_TypeError, (char*)"expecting arguments (int midiNoteNumber)"); | ||
return NULL; | ||
} | ||
|
||
std::string note = midi2note( long( PyLong_AsLong(arg) ) ); | ||
const char *c_note = note.c_str(); | ||
return PyString_FromString( c_note ); | ||
} | ||
|
||
static PyObject* | ||
noteToMidi(PyObject* notUsed, PyObject* arg) { | ||
|
||
if (!PyString_Check(arg)) { | ||
PyErr_SetString(PyExc_TypeError, (char*)"expecting arguments (string note)"); | ||
return NULL; | ||
} | ||
|
||
int octave = note2midi( PyString_AS_STRING(arg) ); | ||
return PyLong_FromLong( int(octave) ); | ||
} | ||
|
||
static PyObject* | ||
noteToRoot(PyObject* notUsed, PyObject* arg) { | ||
|
||
if (!PyString_Check(arg)) { | ||
PyErr_SetString(PyExc_TypeError, (char*)"expecting arguments (string note)"); | ||
return NULL; | ||
} | ||
|
||
std::string root = note2root( PyString_AS_STRING(arg) ); | ||
const char *c_root = root.c_str(); | ||
return PyString_FromString( c_root ); | ||
} | ||
|
||
static PyObject* | ||
noteToOctave(PyObject* notUsed, PyObject* arg) { | ||
|
||
if (!PyString_Check(arg)) { | ||
PyErr_SetString(PyExc_TypeError, (char*)"expecting arguments (string note)"); | ||
return NULL; | ||
} | ||
|
||
int octave = note2octave( PyString_AS_STRING(arg) ); | ||
return PyLong_FromLong( int(octave) ); | ||
} | ||
|
||
static PyObject* | ||
hzToNote(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
if (argsV.size() != 2 || | ||
(!PyFloat_Check(argsV[0]) || !PyFloat_Check(argsV[1]))) { | ||
PyErr_SetString(PyExc_ValueError, "expecting arguments (Real hertz, Real tuningFrequency)"); | ||
return NULL; | ||
} | ||
|
||
std::string note = hz2note( Real( PyFloat_AS_DOUBLE(argsV[0]) ), Real( PyFloat_AS_DOUBLE(argsV[1]) ) ); | ||
const char *c_note = note.c_str(); | ||
return PyString_FromString( c_note ); | ||
} | ||
|
||
static PyObject* | ||
noteToHz(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
if (argsV.size() != 2 || | ||
(!PyString_Check(argsV[0]) || !PyFloat_Check(argsV[1]))) { | ||
PyErr_SetString(PyExc_ValueError, "expecting arguments (string note, Real tuningFrequency)"); | ||
return NULL; | ||
} | ||
|
||
Real hz = note2hz( PyString_AS_STRING(argsV[0]), Real( PyFloat_AS_DOUBLE(argsV[1]) ) ); | ||
return PyFloat_FromDouble( hz ); | ||
} | ||
|
||
static PyObject* | ||
velocityToDb(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
if (argsV.size() != 2 || | ||
(!PyLong_Check(argsV[0]) || !PyFloat_Check(argsV[1]))) { | ||
PyErr_SetString(PyExc_ValueError, "expecting arguments (int velocity, Real hearingThreshold)"); | ||
return NULL; | ||
} | ||
|
||
Real db = velocity2db( long( PyLong_AsLong(argsV[0]) ), Real( PyFloat_AS_DOUBLE(argsV[1]) ) ); | ||
return PyFloat_FromDouble( db ); | ||
} | ||
|
||
static PyObject* | ||
dbToVelocity(PyObject* notUsed, PyObject* args) { | ||
// parse args to get Source alg, name and source alg and source name | ||
vector<PyObject*> argsV = unpack(args); | ||
if (argsV.size() != 2 || | ||
(!PyFloat_Check(argsV[0]) || !PyFloat_Check(argsV[1]))) { | ||
PyErr_SetString(PyExc_ValueError, "expecting arguments (Real decibels, Real hearingThreshold)"); | ||
return NULL; | ||
} | ||
|
||
long velocity = db2velocity( Real( PyFloat_AS_DOUBLE(argsV[0])), Real( PyFloat_AS_DOUBLE(argsV[1])) ); | ||
return PyLong_FromLong( int(velocity) ); | ||
} | ||
|
||
static PyObject* | ||
getEquivalentKey(PyObject* notUsed, PyObject* arg) { | ||
|
@@ -1001,6 +1162,18 @@ static PyMethodDef Essentia__Methods[] = { | |
{ "hz2bark", hzToBark, METH_O, "Converts a frequency in Hz to a bark band" }, | ||
{ "mel2hz", melToHz, METH_O, "Converts a mel band to frequency in Hz" }, | ||
{ "hz2mel", hzToMel, METH_O, "Converts a frequency in Hz to a mel band" }, | ||
{ "midi2hz", midiToHz, METH_VARARGS, "Converts a midi note number to frequency in Hz" }, | ||
{ "hz2midi", hzToMidi, METH_VARARGS, "Converts a frequency in Hz to a midi note number" }, | ||
{ "hz2cents", hzToCents, METH_VARARGS, "Returns the cents distance between two frequencies in Hz" }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we use the |
||
{ "cents2hz", centsToHz, METH_VARARGS, "Returns the frequency from a frequency in Hz and cents distance" }, | ||
{ "midi2note", midiToNote, METH_O, "Converts a midi note number to note applying the international pitch standard (A4=440Hz)" }, | ||
{ "note2midi", noteToMidi, METH_O, "Converts note (applying the international pitch standard A4=440Hz) to midi note number" }, | ||
{ "note2root", noteToRoot, METH_O, "Returns the root of a note" }, | ||
{ "note2octave", noteToOctave, METH_O, "Returns the octave of a note" }, | ||
{ "hz2note", hzToNote, METH_VARARGS, "Converts a frequency in Hz to a note - applying the international pitch standard A4=440Hz" }, | ||
{ "note2hz", noteToHz, METH_VARARGS, "Converts a note - applying the international pitch standard A4=440Hz - into a frequency in Hz" }, | ||
{ "velocity2db", velocityToDb, METH_VARARGS, "Converts a velocity to a measure in dB" }, | ||
{ "db2velocity", dbToVelocity, METH_VARARGS, "Converts a dB measure of power to velocity [0-127]" }, | ||
{ "lin2db", linToDb, METH_O, "Converts a linear measure of power to a measure in dB" }, | ||
{ "db2lin", dbToLin, METH_O, "Converts a dB measure of power to a linear measure" }, | ||
{ "db2pow", dbToPow, METH_O, "Converts a dB measure of power to a linear measure" }, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
frequencyA
vsfrequencyB
can be unclear to users. Maybe we could use a different naming forfrequencyB
likereferenceFrequency
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that makes sense. I doubted with
tuningFrequency
butreferenceFrequency
works better. Thanks.