You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
6.3KB

  1. #include "Core.hpp"
  2. #include <iostream>
  3. float Core::getPitchFromVolts(float inVolts, float inRoot, float inScale, int *outRoot, int *outScale, int *outNote, int *outDegree) {
  4. // get the root note and scale
  5. int currRoot = getKeyFromVolts(inRoot);
  6. int currScale = getScaleFromVolts(inScale);
  7. if (debug && stepX % poll == 0) {
  8. std::cout << "QUANT " << stepX << " Root in: " << inRoot << " Root out: " << currRoot<< " Scale in: " << inScale << " Scale out: " << currScale << std::endl;
  9. }
  10. float outVolts = getPitchFromVolts(inVolts, currRoot, currScale, outNote, outDegree);
  11. *outRoot = currRoot;
  12. *outScale = currScale;
  13. return outVolts;
  14. }
  15. float Core::getPitchFromVolts(float inVolts, int currRoot, int currScale, int *outNote, int *outDegree) {
  16. int *curScaleArr;
  17. int notesInScale = 0;
  18. switch (currScale){
  19. case SCALE_CHROMATIC: curScaleArr = ASCALE_CHROMATIC; notesInScale=LENGTHOF(ASCALE_CHROMATIC); break;
  20. case SCALE_IONIAN: curScaleArr = ASCALE_IONIAN; notesInScale=LENGTHOF(ASCALE_IONIAN); break;
  21. case SCALE_DORIAN: curScaleArr = ASCALE_DORIAN; notesInScale=LENGTHOF(ASCALE_DORIAN); break;
  22. case SCALE_PHRYGIAN: curScaleArr = ASCALE_PHRYGIAN; notesInScale=LENGTHOF(ASCALE_PHRYGIAN); break;
  23. case SCALE_LYDIAN: curScaleArr = ASCALE_LYDIAN; notesInScale=LENGTHOF(ASCALE_LYDIAN); break;
  24. case SCALE_MIXOLYDIAN: curScaleArr = ASCALE_MIXOLYDIAN; notesInScale=LENGTHOF(ASCALE_MIXOLYDIAN); break;
  25. case SCALE_AEOLIAN: curScaleArr = ASCALE_AEOLIAN; notesInScale=LENGTHOF(ASCALE_AEOLIAN); break;
  26. case SCALE_LOCRIAN: curScaleArr = ASCALE_LOCRIAN; notesInScale=LENGTHOF(ASCALE_LOCRIAN); break;
  27. case SCALE_MAJOR_PENTA: curScaleArr = ASCALE_MAJOR_PENTA; notesInScale=LENGTHOF(ASCALE_MAJOR_PENTA); break;
  28. case SCALE_MINOR_PENTA: curScaleArr = ASCALE_MINOR_PENTA; notesInScale=LENGTHOF(ASCALE_MINOR_PENTA); break;
  29. case SCALE_HARMONIC_MINOR: curScaleArr = ASCALE_HARMONIC_MINOR; notesInScale=LENGTHOF(ASCALE_HARMONIC_MINOR); break;
  30. case SCALE_BLUES: curScaleArr = ASCALE_BLUES; notesInScale=LENGTHOF(ASCALE_BLUES); break;
  31. default: curScaleArr = ASCALE_CHROMATIC; notesInScale=LENGTHOF(ASCALE_CHROMATIC);
  32. }
  33. // get the octave
  34. int octave = floor(inVolts);
  35. float closestVal = 10.0;
  36. float closestDist = 10.0;
  37. int noteFound = 0;
  38. if (debug && stepX % poll == 0) {
  39. std::cout << "QUANT Octave: " << octave << " Scale: " << scaleNames[currScale] << " Root: " << noteNames[currRoot] << std::endl;
  40. }
  41. float octaveOffset = 0;
  42. if (currRoot != 0) {
  43. octaveOffset = (12 - currRoot) / 12.0;
  44. }
  45. if (debug && stepX % poll == 0) {
  46. std::cout << "QUANT Octave: " << octave << " currRoot: " << currRoot << " -> Offset: " << octaveOffset << " inVolts: " << inVolts << std::endl;
  47. }
  48. float fOctave = (float)octave - octaveOffset;
  49. int scaleIndex = 0;
  50. int searchOctave = 0;
  51. do {
  52. int degree = curScaleArr[scaleIndex]; // 0 - 11!
  53. float fVoltsAboveOctave = searchOctave + degree / 12.0;
  54. float fScaleNoteInVolts = fOctave + fVoltsAboveOctave;
  55. float distAway = fabs(inVolts - fScaleNoteInVolts);
  56. if (debug && stepX % poll == 0) {
  57. std::cout << "QUANT input: " << inVolts
  58. << " index: " << scaleIndex
  59. << " root: " << currRoot
  60. << " octave: " << fOctave
  61. << " degree: " << degree
  62. << " V above O: " << fVoltsAboveOctave
  63. << " note in V: " << fScaleNoteInVolts
  64. << " distance: " << distAway
  65. << std::endl;
  66. }
  67. // Assume that the list of notes is ordered, so there is an single inflection point at the minimum value
  68. if (distAway >= closestDist){
  69. break;
  70. } else {
  71. // Let's remember this
  72. closestVal = fScaleNoteInVolts;
  73. closestDist = distAway;
  74. }
  75. scaleIndex++;
  76. if (scaleIndex == notesInScale - 1) {
  77. scaleIndex = 0;
  78. searchOctave++;
  79. }
  80. } while (true);
  81. if(scaleIndex == 0) {
  82. noteFound = notesInScale - 2; // NIS is a count, not index
  83. } else {
  84. noteFound = scaleIndex - 1;
  85. }
  86. if (debug && stepX % poll == 0) {
  87. std::cout << "QUANT NIS: " << notesInScale << " scaleIndex: " << scaleIndex << " NF: " << noteFound << std::endl;
  88. }
  89. int currNote = (currRoot + curScaleArr[noteFound]) % 12; // So this is the nth note of the scale;
  90. // case in point, V=0, Scale = F#m returns the 6th note, which should be C#
  91. if (debug && stepX % poll == 0) {
  92. // Dump the note and degree, mod the size in case where we have wrapped round
  93. std::cout << "QUANT Found index in scale: " << noteFound << ", currNote: " << currNote;
  94. std::cout << " This is scale note: " << curScaleArr[noteFound] << " (Interval: " << intervalNames[curScaleArr[noteFound]] << ")";
  95. std::cout << ": " << inVolts << " -> " << closestVal << std::endl;
  96. }
  97. *outNote = currNote;
  98. *outDegree = curScaleArr[noteFound];
  99. return closestVal;
  100. }
  101. void Core::getRootFromMode(int inMode, int inRoot, int inTonic, int *currRoot, int *quality) {
  102. *quality = ModeQuality[inMode][inTonic];
  103. int positionRelativeToStartOfScale = tonicIndex[inMode + inTonic];
  104. int positionStartOfScale = scaleIndex[inMode];
  105. // FIXME should be mapped into the Circle of Fifths??
  106. *currRoot = inRoot + noteIndex[positionStartOfScale + positionRelativeToStartOfScale];
  107. if (*currRoot < 0) {
  108. *currRoot += 12;
  109. }
  110. if (*currRoot > 11) {
  111. *currRoot -= 12;
  112. }
  113. // Quantizer q;
  114. //
  115. // std::cout << "Mode: " << inMode
  116. // << " Root: " << q.noteNames[inRoot]
  117. // << " Tonic: " << q.tonicNames[inTonic]
  118. // << " Scale Pos: " << positionStartOfScale
  119. // << " Rel Pos: " << positionRelativeToStartOfScale
  120. // << " Note Index: " << positionStartOfScale + positionRelativeToStartOfScale
  121. // << " Note: " << noteIndex[positionStartOfScale + positionRelativeToStartOfScale]
  122. // << " Offset: " << ModeOffset[inMode][inTonic]
  123. // << " Output: " << *currRoot
  124. // << " " << q.noteNames[*currRoot]
  125. // << std::endl;
  126. }
  127. Core & CoreUtil() {
  128. static Core core;
  129. return core;
  130. }
  131. // http://c-faq.com/lib/gaussian.html
  132. double Core::gaussrand() {
  133. static double U, V;
  134. static int phase = 0;
  135. double Z;
  136. if(phase == 0) {
  137. U = (rand() + 1.) / (RAND_MAX + 2.);
  138. V = rand() / (RAND_MAX + 1.);
  139. Z = sqrt(-2 * log(U)) * sin(2 * M_PI * V);
  140. } else
  141. Z = sqrt(-2 * log(U)) * cos(2 * M_PI * V);
  142. phase = 1 - phase;
  143. return Z;
  144. }
  145. int Core::ipow(int base, int exp) {
  146. int result = 1;
  147. while (exp)
  148. {
  149. if (exp & 1)
  150. result *= base;
  151. exp >>= 1;
  152. base *= base;
  153. }
  154. return result;
  155. }