mirror of
https://codeberg.org/armin/wavetable.git
synced 2026-09-01 22:10:47 +02:00
Allow wavetables without metadata
This commit is contained in:
parent
6fbf3e1810
commit
c9365c8fe0
5 changed files with 94 additions and 28 deletions
|
|
@ -7,6 +7,7 @@
|
||||||
- Draw all phase dots for LFO and Step LFO
|
- Draw all phase dots for LFO and Step LFO
|
||||||
- Try and make delay less zippery (WIP)
|
- Try and make delay less zippery (WIP)
|
||||||
- Scroll wheel can adjust combo boxes
|
- Scroll wheel can adjust combo boxes
|
||||||
|
- Fixed presets getting deleted when renaming
|
||||||
|
|
||||||
1.0.3:
|
1.0.3:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
{ "id": "Spread", "x": "prevR()", "y": "prevY()", "w": 56, "h": 70 },
|
{ "id": "Spread", "x": "prevR()", "y": "prevY()", "w": 56, "h": 70 },
|
||||||
{ "id": "Formant", "x": "prevR()", "y": "prevY()", "w": 56, "h": 70 },
|
{ "id": "Formant", "x": "prevR()", "y": "prevY()", "w": 56, "h": 70 },
|
||||||
{ "id": "Bend", "x": "prevR()", "y": "prevY()", "w": 56, "h": 70 },
|
{ "id": "Bend", "x": "prevR()", "y": "prevY()", "w": 56, "h": 70 },
|
||||||
{ "id": "wt", "x": "prevR()", "y": 23, "r": "parW()", "b": "parH()" }
|
{ "id": "wt", "x": "prevR()", "y": 23, "r": "parW()", "b": "parH()" },
|
||||||
|
{ "id": "add", "r": "parW() - 8", "b": "parH() - 8", "w": 16, "h": 16 }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ "id": "noise", "x": "0", "y": "prevB()+1", "w": 120, "h": 163, "children":
|
{ "id": "noise", "x": "0", "y": "prevB()+1", "w": 120, "h": 163, "children":
|
||||||
|
|
|
||||||
|
|
@ -24,25 +24,41 @@ public:
|
||||||
|
|
||||||
addEnable (osc.enable);
|
addEnable (osc.enable);
|
||||||
|
|
||||||
addControl (new gin::Knob (osc.pos), 0, 0);
|
addControl (new gin::Knob (osc.pos));
|
||||||
addControl (new gin::Knob (osc.tune, true), 1, 0);
|
addControl (new gin::Knob (osc.tune, true));
|
||||||
addControl (new gin::Knob (osc.finetune, true), 2, 0);
|
addControl (new gin::Knob (osc.finetune, true));
|
||||||
addControl (new gin::Knob (osc.level), 3, 0);
|
addControl (new gin::Knob (osc.level));
|
||||||
addControl (new gin::Knob (osc.pan, true), 4, 0);
|
addControl (new gin::Knob (osc.pan, true));
|
||||||
|
|
||||||
addControl (new gin::Select (osc.voices), 0, 1);
|
addControl (new gin::Select (osc.voices));
|
||||||
addControl (detune = new gin::Knob (osc.detune), 1, 1);
|
addControl (detune = new gin::Knob (osc.detune));
|
||||||
addControl (spread = new gin::Knob (osc.spread), 2, 1);
|
addControl (spread = new gin::Knob (osc.spread));
|
||||||
addControl (new gin::Knob (osc.formant, true), 3, 1);
|
addControl (new gin::Knob (osc.formant, true));
|
||||||
addControl (new gin::Knob (osc.bend, true), 4, 1);
|
addControl (new gin::Knob (osc.bend, true));
|
||||||
|
|
||||||
watchParam (osc.voices);
|
watchParam (osc.voices);
|
||||||
|
|
||||||
wt = new gin::WavetableComponent();
|
wt = new gin::WavetableComponent();
|
||||||
wt->setName ("wt");
|
wt->setName ("wt");
|
||||||
wt->setWavetables (idx == 0 ? &proc.osc1Tables : &proc.osc2Tables);
|
wt->setWavetables (idx == 0 ? &proc.osc1Tables : &proc.osc2Tables);
|
||||||
wt->onFileDrop = [this] (const juce::File& f) { proc.loadUserWavetable (idx, f); };
|
wt->onFileDrop = [this] (const juce::File& f) { loadUserWavetable (f); };
|
||||||
addControl (wt, 5, 0, 3, 2);
|
addControl (wt);
|
||||||
|
|
||||||
|
addAndMakeVisible (addButton);
|
||||||
|
addButton.onClick = [this]
|
||||||
|
{
|
||||||
|
auto chooser = std::make_shared<juce::FileChooser> (juce::String ("Load Wavetable"), juce::File(), juce::String ("*.wav"));
|
||||||
|
|
||||||
|
auto chooserFlags = juce::FileBrowserComponent::canSelectFiles | juce::FileBrowserComponent::openMode;
|
||||||
|
chooser->launchAsync (chooserFlags, [this, chooser] (const juce::FileChooser&)
|
||||||
|
{
|
||||||
|
auto f = chooser->getResult();
|
||||||
|
if (! f.existsAsFile())
|
||||||
|
return;
|
||||||
|
|
||||||
|
loadUserWavetable (f);
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
timer.startTimerHz (60);
|
timer.startTimerHz (60);
|
||||||
timer.onTimer = [this]
|
timer.onTimer = [this]
|
||||||
|
|
@ -66,6 +82,34 @@ public:
|
||||||
proc.osc2Table.removeListener (this);
|
proc.osc2Table.removeListener (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadUserWavetable (const juce::File& f)
|
||||||
|
{
|
||||||
|
auto sz = gin::getWavetableSize (f);
|
||||||
|
if (sz <= 0)
|
||||||
|
{
|
||||||
|
auto w = std::make_shared<gin::PluginAlertWindow> ("Import Wavetable", "Wav file does not contain Wavetable metadata. What is the wavetable size?", juce::AlertWindow::NoIcon, getParentComponent());
|
||||||
|
w->setLookAndFeel (proc.lf.get());
|
||||||
|
w->addComboBox ("size", { "256", "512", "1024", "2048" }, "Samples per table:");
|
||||||
|
w->getComboBoxComponent ("size")->setSelectedItemIndex (3);
|
||||||
|
|
||||||
|
w->addButton ("OK", 1, juce::KeyPress (juce::KeyPress::returnKey));
|
||||||
|
w->addButton ("Cancel", 0, juce::KeyPress (juce::KeyPress::escapeKey));
|
||||||
|
|
||||||
|
w->runAsync (*getParentComponent(), [this, w, f] (int ret)
|
||||||
|
{
|
||||||
|
auto userSize = w->getComboBoxComponent ("size")->getText().getIntValue();
|
||||||
|
|
||||||
|
w->setVisible (false);
|
||||||
|
if (ret == 1)
|
||||||
|
proc.loadUserWavetable (idx, f, userSize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proc.loadUserWavetable (idx, f, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mouseUp (const juce::MouseEvent& e) override
|
void mouseUp (const juce::MouseEvent& e) override
|
||||||
{
|
{
|
||||||
auto& h = getHeader();
|
auto& h = getHeader();
|
||||||
|
|
@ -145,6 +189,7 @@ public:
|
||||||
|
|
||||||
gin::SVGButton nextButton { "next", gin::Assets::next };
|
gin::SVGButton nextButton { "next", gin::Assets::next };
|
||||||
gin::SVGButton prevButton { "prev", gin::Assets::prev };
|
gin::SVGButton prevButton { "prev", gin::Assets::prev };
|
||||||
|
gin::SVGButton addButton { "add", gin::Assets::add };
|
||||||
};
|
};
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
|
||||||
|
|
@ -543,23 +543,23 @@ void WavetableAudioProcessor::reloadWavetables()
|
||||||
if (userTable1.getSize() > 0)
|
if (userTable1.getSize() > 0)
|
||||||
{
|
{
|
||||||
if (shouldLoad (0, osc1Table.toString(), sr))
|
if (shouldLoad (0, osc1Table.toString(), sr))
|
||||||
loadWaveTable (osc1Tables, sr, userTable1, "wav");
|
loadWaveTable (osc1Tables, sr, userTable1, "wav", osc1Size);
|
||||||
}
|
}
|
||||||
else if (auto mb = loadMemory (osc1Table.toString()); mb.getSize() > 0)
|
else if (auto mb = loadMemory (osc1Table.toString()); mb.getSize() > 0)
|
||||||
{
|
{
|
||||||
if (shouldLoad (0, osc1Table.toString(), sr))
|
if (shouldLoad (0, osc1Table.toString(), sr))
|
||||||
loadWaveTable (osc1Tables, sr, mb, "flac");
|
loadWaveTable (osc1Tables, sr, mb, "flac", osc1Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userTable2.getSize() > 0)
|
if (userTable2.getSize() > 0)
|
||||||
{
|
{
|
||||||
if (shouldLoad (0, osc2Table.toString(), sr))
|
if (shouldLoad (0, osc2Table.toString(), sr))
|
||||||
loadWaveTable (osc2Tables, sr, userTable2, "wav");
|
loadWaveTable (osc2Tables, sr, userTable2, "wav", osc2Size);
|
||||||
}
|
}
|
||||||
else if (auto mb = loadMemory (osc2Table.toString()); mb.getSize() > 0)
|
else if (auto mb = loadMemory (osc2Table.toString()); mb.getSize() > 0)
|
||||||
{
|
{
|
||||||
if (shouldLoad (1, osc2Table.toString(), sr))
|
if (shouldLoad (1, osc2Table.toString(), sr))
|
||||||
loadWaveTable (osc2Tables, sr, mb, "flac");
|
loadWaveTable (osc2Tables, sr, mb, "flac", osc2Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,20 +590,24 @@ void WavetableAudioProcessor::incWavetable (int osc, int delta)
|
||||||
reloadWavetables();
|
reloadWavetables();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WavetableAudioProcessor::loadUserWavetable (int osc, const juce::File f)
|
bool WavetableAudioProcessor::loadUserWavetable (int osc, const juce::File& f, int sz)
|
||||||
{
|
{
|
||||||
auto& table = osc == 0 ? osc1Tables : osc2Tables;
|
auto& table = osc == 0 ? osc1Tables : osc2Tables;
|
||||||
auto& mb = osc == 0 ? userTable1 : userTable2;
|
auto& mb = osc == 0 ? userTable1 : userTable2;
|
||||||
auto& name = osc == 0 ? osc1Table : osc2Table;
|
auto& name = osc == 0 ? osc1Table : osc2Table;
|
||||||
|
auto& size = osc == 0 ? osc1Size : osc2Size;
|
||||||
|
|
||||||
juce::MemoryBlock raw;
|
juce::MemoryBlock raw;
|
||||||
f.loadFileAsData (raw);
|
f.loadFileAsData (raw);
|
||||||
|
|
||||||
if (loadWaveTable (table, gin::Processor::getSampleRate(), raw, "wav"))
|
if (loadWaveTable (table, gin::Processor::getSampleRate(), raw, "wav", sz))
|
||||||
{
|
{
|
||||||
mb = raw;
|
mb = raw;
|
||||||
name = f.getFileNameWithoutExtension();
|
name = f.getFileNameWithoutExtension();
|
||||||
|
size = sz;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
@ -614,6 +618,9 @@ void WavetableAudioProcessor::stateUpdated()
|
||||||
osc1Table = state.getProperty ("wt1");
|
osc1Table = state.getProperty ("wt1");
|
||||||
osc2Table = state.getProperty ("wt2");
|
osc2Table = state.getProperty ("wt2");
|
||||||
|
|
||||||
|
osc1Size = state.getProperty ("wt1Size", -1);
|
||||||
|
osc2Size = state.getProperty ("wt2Size", -1);
|
||||||
|
|
||||||
userTable1.reset();
|
userTable1.reset();
|
||||||
userTable2.reset();
|
userTable2.reset();
|
||||||
|
|
||||||
|
|
@ -632,6 +639,9 @@ void WavetableAudioProcessor::updateState()
|
||||||
state.setProperty ("wt1", osc1Table, nullptr);
|
state.setProperty ("wt1", osc1Table, nullptr);
|
||||||
state.setProperty ("wt2", osc2Table, nullptr);
|
state.setProperty ("wt2", osc2Table, nullptr);
|
||||||
|
|
||||||
|
state.setProperty ("wt1Size", osc1Size, nullptr);
|
||||||
|
state.setProperty ("wt2Size", osc2Size, nullptr);
|
||||||
|
|
||||||
state.setProperty ("wt1Data", userTable1.toBase64Encoding(), nullptr);
|
state.setProperty ("wt1Data", userTable1.toBase64Encoding(), nullptr);
|
||||||
state.setProperty ("wt2Data", userTable2.toBase64Encoding(), nullptr);
|
state.setProperty ("wt2Data", userTable2.toBase64Encoding(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
@ -979,7 +989,7 @@ void WavetableAudioProcessor::updateParams (int newBlockSize)
|
||||||
outputGain.setGain (modMatrix.getValue (globalParams.level));
|
outputGain.setGain (modMatrix.getValue (globalParams.level));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WavetableAudioProcessor::loadWaveTable (juce::OwnedArray<gin::BandLimitedLookupTable>& table, double sr, const juce::MemoryBlock& wav, const juce::String& format)
|
bool WavetableAudioProcessor::loadWaveTable (juce::OwnedArray<gin::BandLimitedLookupTable>& table, double sr, const juce::MemoryBlock& wav, const juce::String& format, int size)
|
||||||
{
|
{
|
||||||
auto is = new juce::MemoryInputStream (wav, false);
|
auto is = new juce::MemoryInputStream (wav, false);
|
||||||
|
|
||||||
|
|
@ -987,13 +997,21 @@ bool WavetableAudioProcessor::loadWaveTable (juce::OwnedArray<gin::BandLimitedLo
|
||||||
{
|
{
|
||||||
if (auto reader = std::unique_ptr<juce::AudioFormatReader> (juce::WavAudioFormat().createReaderFor (is, true)))
|
if (auto reader = std::unique_ptr<juce::AudioFormatReader> (juce::WavAudioFormat().createReaderFor (is, true)))
|
||||||
{
|
{
|
||||||
if (auto sz = gin::getWavetableSize (wav); sz > 0)
|
if (size <= 0)
|
||||||
|
size = gin::getWavetableSize (wav);
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
{
|
{
|
||||||
juce::AudioSampleBuffer buf (1, int (reader->lengthInSamples));
|
int samplesToUse = int (reader->lengthInSamples);
|
||||||
reader->read (&buf, 0, int (reader->lengthInSamples), 0, true, false);
|
int frames = samplesToUse / size;
|
||||||
|
|
||||||
|
samplesToUse = frames * size;
|
||||||
|
|
||||||
|
juce::AudioSampleBuffer buf (1, samplesToUse);
|
||||||
|
reader->read (&buf, 0, samplesToUse, 0, true, false);
|
||||||
|
|
||||||
juce::OwnedArray<gin::BandLimitedLookupTable> t;
|
juce::OwnedArray<gin::BandLimitedLookupTable> t;
|
||||||
loadWavetables (t, sr, buf, reader->sampleRate, sz);
|
loadWavetables (t, sr, buf, reader->sampleRate, size);
|
||||||
|
|
||||||
juce::ScopedLock sl (dspLock);
|
juce::ScopedLock sl (dspLock);
|
||||||
std::swap (t, table);
|
std::swap (t, table);
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ public:
|
||||||
|
|
||||||
void reloadWavetables();
|
void reloadWavetables();
|
||||||
void incWavetable (int osc, int delta);
|
void incWavetable (int osc, int delta);
|
||||||
void loadUserWavetable (int osc, const juce::File f);
|
bool loadUserWavetable (int osc, const juce::File& f, int sz);
|
||||||
|
|
||||||
void applyEffects (juce::AudioSampleBuffer& buffer);
|
void applyEffects (juce::AudioSampleBuffer& buffer);
|
||||||
bool loadWaveTable (juce::OwnedArray<gin::BandLimitedLookupTable>& table, double sr, const juce::MemoryBlock& wav, const juce::String& format);
|
bool loadWaveTable (juce::OwnedArray<gin::BandLimitedLookupTable>& table, double sr, const juce::MemoryBlock& wav, const juce::String& format, int size);
|
||||||
|
|
||||||
// Voice Params
|
// Voice Params
|
||||||
struct OSCParams
|
struct OSCParams
|
||||||
|
|
@ -261,6 +261,7 @@ public:
|
||||||
|
|
||||||
juce::Value osc1Table, osc2Table;
|
juce::Value osc1Table, osc2Table;
|
||||||
juce::MemoryBlock userTable1, userTable2;
|
juce::MemoryBlock userTable1, userTable2;
|
||||||
|
int osc1Size = -1, osc2Size = -1;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
gin::ModMatrix modMatrix;
|
gin::ModMatrix modMatrix;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue