Skip to content

Commit 37e9c2e

Browse files
committed
#38 Add MTS client.
1 parent e7f5a03 commit 37e9c2e

File tree

13 files changed

+1211
-12
lines changed

13 files changed

+1211
-12
lines changed

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ source_group(Source
113113
${CMAKE_CURRENT_SOURCE_DIR}/Source/Parameters.cpp
114114
)
115115

116+
source_group(Source\\mts
117+
FILES
118+
${CMAKE_CURRENT_SOURCE_DIR}/Source/mts/libMTSClient.h
119+
${CMAKE_CURRENT_SOURCE_DIR}/Source/mts/libMTSClient.cpp
120+
)
121+
116122
source_group(Source\\ui
117123
FILES
118124
${CMAKE_CURRENT_SOURCE_DIR}/Source/ui/CustomLookAndFeel.h

Source/PluginEditor.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ AeolusAudioProcessorEditor::AeolusAudioProcessorEditor (AeolusAudioProcessor& p)
4949
, _volumeLevelL{p.getEngine().getVolumeLevel().left, ui::LevelIndicator::Orientation::Horizontal}
5050
, _volumeLevelR{p.getEngine().getVolumeLevel().right, ui::LevelIndicator::Orientation::Horizontal}
5151
, _tuningButton{"tuningButton", DrawableButton::ImageFitted}
52+
, _mtsConnectedLabel{{}, "connected to MTS master"}
53+
, _mtsDisconnectedLabel{{}, "no MTS master found"}
5254
, _panicButton{"PANIC"}
5355
, _cancelButton{"Cancel"}
5456
, _midiControlChannelLabel{{}, {"Control"}}
@@ -132,19 +134,26 @@ AeolusAudioProcessorEditor::AeolusAudioProcessorEditor (AeolusAudioProcessor& p)
132134

133135
_tuningButton.onClick = [this] {
134136
auto content = std::make_unique<ui::GlobalTuningComponent>();
135-
content->setSize(240, 144);
137+
content->setSize(240, 182);
136138
auto* contentPtr = content.get();
137139

138140
auto& box = CallOutBox::launchAsynchronously(std::move(content), _tuningButton.getBounds(), this);
139141
contentPtr->onCancel = [&box] { box.dismiss(); };
140142
contentPtr->onOk = [&box, contentPtr] {
143+
auto* g = aeolus::EngineGlobal::getInstance();
144+
const bool mtsWasEnabled{ g->isMTSEnabled() };
145+
bool mtsChanged{ contentPtr->isMTSTuningEnabled() != mtsWasEnabled };
146+
141147
const float freq = contentPtr->getTuningFrequency();
142148
const auto scaleType = contentPtr->getTuningScaleType();
143149

144-
auto* g = aeolus::EngineGlobal::getInstance();
145-
const bool changed = (g->getTuningFrequency() != freq) || (g->getScale().getType() != scaleType);
150+
const bool scaleChanged = (g->getTuningFrequency() != freq) || (g->getScale().getType() != scaleType);
146151

147-
if (changed) {
152+
if (mtsChanged) {
153+
g->setMTSEnabled(contentPtr->isMTSTuningEnabled());
154+
}
155+
156+
if (scaleChanged) {
148157
g->setTuningFrequency(freq);
149158
g->setScaleType(scaleType);
150159
g->rebuildRankwaves();
@@ -155,6 +164,12 @@ AeolusAudioProcessorEditor::AeolusAudioProcessorEditor (AeolusAudioProcessor& p)
155164
};
156165
};
157166

167+
addAndMakeVisible(_mtsConnectedLabel);
168+
addAndMakeVisible(_mtsDisconnectedLabel);
169+
170+
_mtsConnectedLabel.setColour(Label::textColourId, Colour(204, 255, 204));
171+
_mtsDisconnectedLabel.setColour(Label::textColourId, Colour(255, 204, 204));
172+
158173
_panicButton.setColour(TextButton::textColourOffId, Colour(0xFF, 0xFF, 0xFF));
159174
_panicButton.setColour(TextButton::buttonColourId, Colour(0xCC, 0x33, 0x00));
160175
addAndMakeVisible(_panicButton);
@@ -276,6 +291,9 @@ void AeolusAudioProcessorEditor::resized()
276291

277292
_tuningButton.setBounds(_volumeSlider.getRight() + 40, margin - 2, 24, 24);
278293

294+
_mtsConnectedLabel.setBounds(_tuningButton.getRight() + 40, margin, 160, 20);
295+
_mtsDisconnectedLabel.setBounds(_mtsConnectedLabel.getBounds());
296+
279297
_panicButton.setBounds(getWidth() - 90, margin, 50, 20);
280298

281299
constexpr int T = margin * 2 + 20;
@@ -341,13 +359,25 @@ void AeolusAudioProcessorEditor::populateDivisions()
341359

342360
void AeolusAudioProcessorEditor::refresh()
343361
{
362+
updateMTS();
344363
updateMeters();
345364
updateDivisionViews();
346365
updateSequencerView();
347366
updateMidiKeyboardRange();
348367
updateMidiKeyboardKeySwitches();
349368
}
350369

370+
void AeolusAudioProcessorEditor::updateMTS()
371+
{
372+
auto* g = aeolus::EngineGlobal::getInstance();
373+
374+
const bool mtsEnabled{ g->isMTSEnabled() };
375+
const bool mtsConnected{ g->isConnectedToMTSMaster() };
376+
377+
_mtsConnectedLabel.setVisible(mtsEnabled && mtsConnected);
378+
_mtsDisconnectedLabel.setVisible(mtsEnabled && !mtsConnected);
379+
}
380+
351381
void AeolusAudioProcessorEditor::updateMeters()
352382
{
353383
auto strLoad = String (int (_audioProcessor.getProcessLoad() * 100.0f)) + "%";

Source/PluginEditor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class AeolusAudioProcessorEditor : public juce::AudioProcessorEditor,
5757
void populateDivisions();
5858
void refresh();
5959

60+
void updateMTS();
6061
void updateMeters();
6162
void updateMidiKeyboardRange();
6263
void updateMidiKeyboardKeySwitches();
@@ -91,6 +92,9 @@ class AeolusAudioProcessorEditor : public juce::AudioProcessorEditor,
9192

9293
juce::DrawableButton _tuningButton;
9394

95+
juce::Label _mtsConnectedLabel;
96+
juce::Label _mtsDisconnectedLabel;
97+
9498
/// Kill all active voices button
9599
juce::TextButton _panicButton;
96100

Source/aeolus/engine.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class PrepareRankwaveJob : ThreadPoolJob
5454
namespace settings {
5555
const static char* tuningFrequency = "tuningFrequency";
5656
const static char* tuningTemperament = "tuningTemperament";
57+
const static char* mtsEnabled = "mtsEnabled";
5758
}
5859

5960
EngineGlobal::EngineGlobal()
@@ -62,6 +63,8 @@ EngineGlobal::EngineGlobal()
6263
, _tuningFrequency(TUNING_FREQUENCY_DEFAULT)
6364
, _globalProperties{}
6465
{
66+
_mtsClient = MTS_RegisterClient();
67+
6568
PropertiesFile::Options options{};
6669

6770
options.applicationName = ProjectInfo::projectName;
@@ -80,6 +83,9 @@ EngineGlobal::EngineGlobal()
8083

8184
EngineGlobal::~EngineGlobal()
8285
{
86+
if (_mtsClient != nullptr)
87+
MTS_DeregisterClient(_mtsClient);
88+
8389
saveSettings();
8490
clearSingletonInstance();
8591
}
@@ -108,6 +114,8 @@ void EngineGlobal::loadSettings()
108114

109115
if (scaleType >= (int)Scale::First && scaleType < (int)Scale::Total)
110116
_scale.setType(static_cast<Scale::Type>(scaleType));
117+
118+
_mtsEnabled = propertiesFile->getBoolValue(settings::mtsEnabled, false);
111119
}
112120
}
113121

@@ -116,6 +124,7 @@ void EngineGlobal::saveSettings()
116124
if (auto* propertiesFile = _globalProperties.getUserSettings()) {
117125
propertiesFile->setValue(settings::tuningFrequency, _tuningFrequency);
118126
propertiesFile->setValue(settings::tuningTemperament, (int)_scale.getType());
127+
propertiesFile->setValue(settings::mtsEnabled, _mtsEnabled);
119128
}
120129

121130
_globalProperties.saveIfNeeded();
@@ -165,6 +174,33 @@ void EngineGlobal::updateStops(float sampleRate)
165174
*/
166175
}
167176

177+
bool EngineGlobal::isConnectedToMTSMaster()
178+
{
179+
if (_mtsClient != nullptr)
180+
return MTS_HasMaster(_mtsClient);
181+
182+
return false;
183+
}
184+
185+
String EngineGlobal::getMTSScaleName()
186+
{
187+
if (_mtsClient == nullptr)
188+
return {};
189+
190+
return String(MTS_GetScaleName(_mtsClient));
191+
}
192+
193+
double EngineGlobal::getMTSNoteToFrequency(int midiNote, int midiChannel)
194+
{
195+
if (_mtsClient == nullptr || !isConnectedToMTSMaster())
196+
{
197+
return _scale.getFrequencyForMidoNote(midiNote);
198+
}
199+
200+
return MTS_NoteToFrequency(_mtsClient, (char)midiNote, (char)midiChannel);
201+
}
202+
203+
168204
void EngineGlobal::rebuildRankwaves()
169205
{
170206
// Prepare all the rankwaves to be retuned

Source/aeolus/engine.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include "aeolus/dsp/convolver.h"
3333
#include "aeolus/dsp/interpolator.h"
3434

35+
#include "mts/libMTSClient.h"
36+
3537
#include <optional>
3638
#include <vector>
3739

@@ -96,6 +98,13 @@ class EngineGlobal : public juce::DeletedAtShutdown
9698
const Scale& getScale() const noexcept { return _scale; }
9799
void setScaleType(Scale::Type type) noexcept { _scale.setType(type); }
98100

101+
bool isConnectedToMTSMaster();
102+
juce::String getMTSScaleName();
103+
double getMTSNoteToFrequency(int midiNote, int midiChannel);
104+
105+
bool isMTSEnabled() const { return _mtsEnabled; }
106+
void setMTSEnabled(bool shouldBeEnabled) { _mtsEnabled = shouldBeEnabled; }
107+
99108
void rebuildRankwaves();
100109

101110
JUCE_DECLARE_SINGLETON (EngineGlobal, false)
@@ -119,6 +128,9 @@ class EngineGlobal : public juce::DeletedAtShutdown
119128
Scale _scale;
120129
float _tuningFrequency;
121130

131+
MTSClient* _mtsClient{};
132+
bool _mtsEnabled{};
133+
122134
juce::ApplicationProperties _globalProperties;
123135
};
124136

Source/aeolus/rankwave.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,10 @@ void Rankwave::createPipes(const Scale& scale, float tuningFrequency)
415415
const auto fd = _model.getFd();
416416

417417
const auto& s = scale.getTable();
418-
float fbase = tuningFrequency * fn / (fd * s[9]);
418+
float fbase = tuningFrequency * fn / fd;
419419

420420
for (int i = _noteMin; i <= _noteMax; ++i) {
421-
auto pipe = std::make_unique<Pipewave>(_model, i - _noteMin, ldexpf(fbase * s[i % 12], i/12 - 5));
421+
auto pipe = std::make_unique<Pipewave>(_model, i - _noteMin, scale.getFrequencyForMidoNote(i, fbase));
422422

423423
_pipes.add(pipe.release());
424424
}
@@ -429,12 +429,11 @@ void Rankwave::retunePipes(const Scale& scale, float tuningFrequency)
429429
const auto fn = _model.getFn();
430430
const auto fd = _model.getFd();
431431

432-
const auto& s = scale.getTable();
433-
float fbase = tuningFrequency * fn / (fd * s[9]);
432+
float fbase = tuningFrequency * fn / fd;
434433

435434
for (int i = _noteMin; i <= _noteMax; ++i) {
436435
Pipewave* pipe = _pipes[i - _noteMin];
437-
pipe->setFrequency(ldexpf(fbase * s[i % 12], i/12 - 5));
436+
pipe->setFrequency(scale.getFrequencyForMidoNote(i, fbase));
438437
pipe->setNeedsToBeRebuilt(true);
439438
}
440439
}

Source/aeolus/scale.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,13 @@ const Scale::Table& Scale::getTable() const
224224
return it->second;
225225
}
226226

227+
float Scale::getFrequencyForMidoNote(int midiNote, float tuningFrequency) const
228+
{
229+
const auto& scaleTable{ getTable() };
230+
float fbase{ tuningFrequency / scaleTable[9] };
231+
return ldexpf(fbase * scaleTable[midiNote % 12], midiNote / 12 - 5);
232+
}
233+
227234
juce::String Scale::getNameForType(Type type)
228235
{
229236
static const std::map<Type, juce::String> names {

Source/aeolus/scale.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ class Scale
5555

5656
const Table& getTable() const;
5757

58+
/**
59+
* Calculate a MIDI note frequency (Hz) given the tuning A frequency.
60+
*/
61+
float getFrequencyForMidoNote(int midiNote, float tuningFrequency = 440.0f) const;
62+
5863
static juce::String getNameForType(Type type);
5964

6065
private:

0 commit comments

Comments
 (0)