Skip to content

Commit

Permalink
Fix a problem where mappings didn't span tuning center
Browse files Browse the repository at this point in the history
If a partial mapping existed and the mapping didnt span
the tuning center (so like you mapped 69-81 with a tuning
center of 60) we were off by an octave. This fix pushes
the mapping to span the tuning center.

Closes #72
Addresses surge-synthesizer/surge#7822
  • Loading branch information
baconpaul committed Oct 7, 2024
1 parent 262337b commit d483836
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 3 deletions.
30 changes: 27 additions & 3 deletions include/TuningsImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,28 @@ inline Tuning::Tuning(const Scale &s_, const KeyboardMapping &k_, bool allowTuni
throw TuningError("Unable to tune to a scale with no notes. Your scale provided " +
std::to_string(s.count) + " notes.");

int useMiddleNote{k.middleNote};
if (k.count > 0)
{
// Is the KBM not spanning the tuning note
auto mapStart = useMiddleNote;
auto mapEnd = useMiddleNote + k.count;
while (mapStart > k.tuningConstantNote)
{
useMiddleNote -= k.count;
mapStart = useMiddleNote;
mapEnd = useMiddleNote + k.count;
// throw std::logic_error("Blah");
}
while (mapEnd < k.tuningConstantNote)
{
useMiddleNote += k.count;
mapStart = useMiddleNote;
mapEnd = useMiddleNote + k.count;
// throw std::logic_error("Blah");
}
}

int kbmRotations{1};
for (const auto &kv : k.keys)
{
Expand Down Expand Up @@ -512,11 +534,11 @@ inline Tuning::Tuning(const Scale &s_, const KeyboardMapping &k_, bool allowTuni
double pitches[N];

int posPitch0 = 256 + k.tuningConstantNote;
int posScale0 = 256 + k.middleNote;
int posScale0 = 256 + useMiddleNote;

double pitchMod = log(k.tuningPitch) / log(2) - 1;

int scalePositionOfTuningNote = k.tuningConstantNote - k.middleNote;
int scalePositionOfTuningNote = k.tuningConstantNote - useMiddleNote;
if (k.count > 0)
{
while (scalePositionOfTuningNote >= k.count)
Expand Down Expand Up @@ -676,10 +698,12 @@ inline Tuning::Tuning(const Scale &s_, const KeyboardMapping &k_, bool allowTuni
** If we mod that by the mapping size we know which note we are on
*/
int mappingKey = distanceFromScale0 % k.count;
int rotations = 0;
if (mappingKey < 0)
{
mappingKey += k.count;
}
// Now have we gone off the end
int rotations = 0;
int dt = distanceFromScale0;
if (dt > 0)
{
Expand Down
23 changes: 23 additions & 0 deletions tests/alltests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,7 @@ TEST_CASE("Skipped Note and Root")
REQUIRE(t.isMidiNoteMapped(60));
REQUIRE(t.isMidiNoteMapped(69));
REQUIRE(t.frequencyForMidiNote(69) == Approx(440.0).margin(0.01));
REQUIRE(t.frequencyForMidiNote(60) == Approx(246.9416506281).margin(0.01));
}

SECTION("Tuning from 59 throws")
Expand Down Expand Up @@ -1185,6 +1186,7 @@ TEST_CASE("Skipped Note and Root")
auto t = Tunings::Tuning(s, k);
REQUIRE(t.isMidiNoteMapped(60));
REQUIRE(t.isMidiNoteMapped(69));
REQUIRE(t.frequencyForMidiNote(60) == Approx(246.9416506281).margin(0.01));
REQUIRE(t.frequencyForMidiNote(69) == Approx(440.0).margin(0.01));
}

Expand All @@ -1196,6 +1198,7 @@ TEST_CASE("Skipped Note and Root")
t = t.withSkippedNotesInterpolated();
REQUIRE(t.isMidiNoteMapped(60));
REQUIRE(t.isMidiNoteMapped(69));
REQUIRE(t.frequencyForMidiNote(60) == Approx(246.9416506281).margin(0.01));
REQUIRE(t.frequencyForMidiNote(69) == Approx(440.0).margin(0.01));
}
}
Expand Down Expand Up @@ -1338,3 +1341,23 @@ TEST_CASE("Retuning API")
}
}
}

TEST_CASE("Surge 7822 non uniform mapping misses scale center")
{
SECTION("At Note 57 - no wrapping")
{
auto scale = Tunings::readSCLFile(testFile("kbm-wrapping-7822/31edo2.scl"));
auto map = Tunings::readKBMFile(testFile("kbm-wrapping-7822/31edo2-subset-57.kbm"));
auto t = Tunings::Tuning(scale, map);
REQUIRE(t.frequencyForMidiNote(60) == Approx(400.0));
REQUIRE(t.frequencyForMidiNote(61) == Approx(418.2936581199));
}
SECTION("At Note 69 - wrapping")
{
auto scale = Tunings::readSCLFile(testFile("kbm-wrapping-7822/31edo2.scl"));
auto map = Tunings::readKBMFile(testFile("kbm-wrapping-7822/31edo2-subset.kbm"));
auto t = Tunings::Tuning(scale, map);
REQUIRE(t.frequencyForMidiNote(60) == Approx(400.0));
REQUIRE(t.frequencyForMidiNote(61) == Approx(418.2936581199));
}
}
29 changes: 29 additions & 0 deletions tests/data/kbm-wrapping-7822/31edo2-subset-57.kbm
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
! foo.kbm
!
! Size of map:
12
! First MIDI note number to retune:
0
! Last MIDI note number to retune:
127
! Middle note where the first entry in the mapping is mapped to:
57
! Reference note for which frequency is given:
60
! Frequency to tune the above note to (floating point e.g. 440.0):
400
! Scale degree to consider as formal octave:
31
! Mapping.
0
3
5
8
10
13
16
18
21
23
26
28
29 changes: 29 additions & 0 deletions tests/data/kbm-wrapping-7822/31edo2-subset.kbm
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
! foo.kbm
!
! Size of map:
12
! First MIDI note number to retune:
0
! Last MIDI note number to retune:
127
! Middle note where the first entry in the mapping is mapped to:
69
! Reference note for which frequency is given:
60
! Frequency to tune the above note to (floating point e.g. 440.0):
400
! Scale degree to consider as formal octave:
31
! Mapping.
0
3
5
8
10
13
16
18
21
23
26
28
36 changes: 36 additions & 0 deletions tests/data/kbm-wrapping-7822/31edo2.scl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
! foo.scl
!

31
!
38.70968
77.41935
116.12903
154.83871
193.54839
232.25806
270.96774
309.67742
348.38710
387.09677
425.80645
464.51613
503.22581
541.93548
580.64516
619.35484
658.06452
696.77419
735.48387
774.19355
812.90323
851.61290
890.32258
929.03226
967.74194
1006.45161
1045.16129
1083.87097
1122.58065
1161.29032
2/1

0 comments on commit d483836

Please sign in to comment.