diff --git a/.gitignore b/.gitignore index e5edbf5..9c31840 100644 --- a/.gitignore +++ b/.gitignore @@ -363,3 +363,6 @@ MigrationBackup/ FodyWeavers.xsd /Builds /bit.7z + +/.vscode +/.vscode/** \ No newline at end of file diff --git a/JuceLibraryCode/JuceLV2Defines.h b/JuceLibraryCode/JuceLV2Defines.h new file mode 100644 index 0000000..20d1966 --- /dev/null +++ b/JuceLibraryCode/JuceLV2Defines.h @@ -0,0 +1,5 @@ +#pragma once + +#ifndef JucePlugin_LV2URI + #define JucePlugin_LV2URI "http://lv2plug.in/ns/ext/uri-map/BitDOS" +#endif diff --git a/JuceLibraryCode/JucePluginDefines.h b/JuceLibraryCode/JucePluginDefines.h index dcd8ebb..4c8375a 100644 --- a/JuceLibraryCode/JucePluginDefines.h +++ b/JuceLibraryCode/JucePluginDefines.h @@ -32,7 +32,7 @@ #define JucePlugin_Build_Unity 0 #endif #ifndef JucePlugin_Build_LV2 - #define JucePlugin_Build_LV2 0 + #define JucePlugin_Build_LV2 1 #endif #ifndef JucePlugin_Enable_IAA #define JucePlugin_Enable_IAA 0 diff --git a/JuceLibraryCode/include_juce_core_CompilationTime.cpp b/JuceLibraryCode/include_juce_core_CompilationTime.cpp new file mode 100644 index 0000000..789042d --- /dev/null +++ b/JuceLibraryCode/include_juce_core_CompilationTime.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_graphics_Harfbuzz.cpp b/JuceLibraryCode/include_juce_graphics_Harfbuzz.cpp new file mode 100644 index 0000000..419cf23 --- /dev/null +++ b/JuceLibraryCode/include_juce_graphics_Harfbuzz.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/Source/Background.cpp b/Source/Background.cpp index 6a0ab96..7d8428e 100644 --- a/Source/Background.cpp +++ b/Source/Background.cpp @@ -14,12 +14,10 @@ //============================================================================== Background::Background(BitDosAudioProcessor& p) : audioProcessor(p) { + const juce::Image bg = juce::ImageCache::getFromMemory(BinaryData::bitdos_gui_png, BinaryData::bitdos_gui_pngSize); + addAndMakeVisible(bgImg); - onBtn.setClickingTogglesState(true); - setRepaintsOnMouseActivity(false); - const juce::Image bg = juce::ImageCache::getFromMemory(BinaryData::bitdos_gui_png, - BinaryData::bitdos_gui_pngSize); if (!bg.isNull()) bgImg.setImage(bg, juce::RectanglePlacement::stretchToFit); else @@ -30,6 +28,9 @@ Background::Background(BitDosAudioProcessor& p) : audioProcessor(p) initImgButton(&onBtn, 1.0f, 0.0f, BinaryData::bitdos_on_png, BinaryData::bitdos_on_pngSize); bgImg.setBufferedToImage(true); + + onBtn.setClickingTogglesState(true); + setRepaintsOnMouseActivity(false); } Background::~Background() @@ -88,8 +89,8 @@ void Background::initImgButton(juce::ImageButton* b, const float up, const float { juce::Image img; - if (b == nullptr) return; - if (imgData == nullptr) return; + jassert(b != nullptr); + jassert(imgData != nullptr); img = juce::ImageCache::getFromMemory(imgData, dataSize); @@ -109,6 +110,4 @@ void Background::initImgButton(juce::ImageButton* b, const float up, const float img, up, juce::Colours::transparentWhite, img, up, juce::Colours::transparentWhite, img, down, juce::Colours::transparentWhite); - - b->setBufferedToImage(true); } diff --git a/Source/NumberScreen.cpp b/Source/NumberScreen.cpp index eed89b4..e86b3fd 100644 --- a/Source/NumberScreen.cpp +++ b/Source/NumberScreen.cpp @@ -46,10 +46,10 @@ void NumberScreen::paint (juce::Graphics& g) { for (int i = 7; i >= 0; i--) { - juce::String bitScreen = juce::String((currentSample & (1 << i)) >> i); + const char bitScreen[] = { static_cast(0x30 + ((currentSample & (1 << i)) >> i)), '\0' }; g.setColour(bits[i].color); - g.drawText(bitScreen, bits[i].rect, juce::Justification::topLeft, false); + g.drawText(juce::String(bitScreen, 2), bits[i].rect, juce::Justification::topLeft, false); g.setColour(juce::Colour(0x20d3d3d3)); @@ -62,7 +62,7 @@ void NumberScreen::paint (juce::Graphics& g) } else { - volEdit(g, 7, 6, (audioProcessor.getPreGain() * 127.5f), editingPreGain); + volEdit(g, 7, 6, (audioProcessor.getPreGain() * 127.5f), editingPreGain); volEdit(g, 4, 3, (audioProcessor.getPostGain() * 127.5f), editingPostGain); volEdit(g, 1, 0, (audioProcessor.getBlend() * 255.0f), editingBlend); @@ -73,6 +73,7 @@ void NumberScreen::paint (juce::Graphics& g) g.drawText("POST GAIN", juce::Rectangle(162, 100, 100, 20), juce::Justification::topLeft, false); g.drawText("BLEND", juce::Rectangle(322, 100, 60, 20), juce::Justification::topLeft, false); } + } void NumberScreen::resized() @@ -81,7 +82,7 @@ void NumberScreen::resized() void NumberScreen::volEdit(juce::Graphics& g, int bit1, int bit2, float param, bool isEditing) { - uint8_t float2nib = (uint8_t)round(param); + uint8_t float2nib = (uint8_t)std::round(param); juce::String bitScreen = juce::String::toHexString((float2nib & ~0x0F) >> 4).toUpperCase(); @@ -129,25 +130,37 @@ void NumberScreen::mouseDown(const juce::MouseEvent& e) editingPreGain = true; if (numClicks >= 2) + { audioProcessor.setPreGain(1.0f); + repaint(bits[7].rect); + repaint(bits[6].rect); + } } - if (bits[4].rect.contains(mouseDownPos) || + else if (bits[4].rect.contains(mouseDownPos) || bits[3].rect.contains(mouseDownPos)) { editingPostGain = true; if (numClicks >= 2) + { audioProcessor.setPostGain(1.0f); + repaint(bits[4].rect); + repaint(bits[3].rect); + } } - if (bits[1].rect.contains(mouseDownPos) || + else if (bits[1].rect.contains(mouseDownPos) || bits[0].rect.contains(mouseDownPos)) { editingBlend = true; if (numClicks >= 2) + { audioProcessor.setBlend(1.0f); + repaint(bits[1].rect); + repaint(bits[0].rect); + } } } } @@ -200,9 +213,7 @@ void NumberScreen::mouseUp(const juce::MouseEvent&) void NumberScreen::mouseExit(const juce::MouseEvent&) { for (int i = 7; i >= 0; i--) - { repaint(bits[i].rect); - } mouseOverBit = -1; } diff --git a/Source/NumberScreen.h b/Source/NumberScreen.h index 9addc52..99ce173 100644 --- a/Source/NumberScreen.h +++ b/Source/NumberScreen.h @@ -40,11 +40,8 @@ class NumberScreen : public juce::Component, void bitInit(); void timerCallback() override; - const juce::Font sansFont = juce::Font(juce::Font::getDefaultSansSerifFontName(), - 18.0f, juce::Font::plain); - - const juce::Font sevenSegFont = juce::Font(juce::Typeface::createSystemTypefaceFor(BinaryData::seg_7_otf, - BinaryData::seg_7_otfSize)); + const juce::Font sansFont = juce::Font(juce::FontOptions(juce::Font::getDefaultSansSerifFontName(), 18.0f, juce::Font::plain)); + const juce::Font sevenSegFont = juce::Font(juce::FontOptions(juce::Typeface::createSystemTypefaceFor(BinaryData::seg_7_otf, BinaryData::seg_7_otfSize))); uint8_t currentSample{ 0 }; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 60c0f0e..d346e32 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -142,22 +142,13 @@ static uint_fast8_t clamp_uint8(const int_fast16_t samp) static float clamp_float(const float samp) { - return (abs(samp) < 1.0) ? samp : (samp < 0) ? -1 : 1 ; + return samp > 1 ? 1.0f : samp < -1 ? -1.0f : samp; } void BitDosAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer&) { - juce::ScopedNoDenormals noDenormals; - auto totalNumInputChannels = getTotalNumInputChannels(); - auto totalNumOutputChannels = getTotalNumOutputChannels(); - - for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) - buffer.clear (i, 0, buffer.getNumSamples()); - - if (paramsUpdated) updateParams(); - if (isBypassed) return; - - int numSamples = buffer.getNumSamples(); + const int totalNumInputChannels = getTotalNumInputChannels(); + const int totalNumOutputChannels = getTotalNumOutputChannels(); const float* inL = buffer.getReadPointer(0); const float* inR = totalNumInputChannels > 1 ? buffer.getReadPointer(1) : nullptr; @@ -165,6 +156,13 @@ void BitDosAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce: float* outL = buffer.getWritePointer(0); float* outR = totalNumOutputChannels > 1 ? buffer.getWritePointer(1) : nullptr; + int numSamples = buffer.getNumSamples(); + + for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) + buffer.clear (i, 0, buffer.getNumSamples()); + + if (isBypassed) return; + while (--numSamples >= 0) { float out[2] = { 0.f, 0.f }; @@ -236,6 +234,15 @@ void BitDosAudioProcessor::getStateInformation (juce::MemoryBlock& destData) { auto state = APVTS.copyState(); std::unique_ptr xml(state.createXml()); + + for(int i = 0; i < xml->getNumChildElements(); i++) + { + juce::String attrib(xml->getChildElement(i)->getStringAttribute("id")); + if(attrib.isEmpty()) continue; + if(!attrib.contains(" ")) continue; + xml->removeChildElement(xml->getChildElement(i), true); + } + copyXmlToBinary(*xml, destData); } @@ -243,84 +250,100 @@ void BitDosAudioProcessor::setStateInformation (const void* data, int sizeInByte { std::unique_ptr xmlState(getXmlFromBinary(data, sizeInBytes)); - if (xmlState.get() != nullptr) - if (xmlState->hasTagName(APVTS.state.getType())) - { - APVTS.replaceState(juce::ValueTree::fromXml(*xmlState)); + if (xmlState.get() == nullptr) return; + if (!xmlState->hasTagName(APVTS.state.getType())) return; - updateParams(); + APVTS.replaceState(juce::ValueTree::fromXml(*xmlState)); - signedMode = (bool)APVTS.state.getProperty("mode"); - isBypassed = (bool)APVTS.state.getProperty("bypass"); + for(int i = 0; i < APVTS.state.getNumChildren(); i++) + { + juce::ValueTree param = APVTS.state.getChild(i); + if (param.getNumProperties() < 2) continue; + valueTreePropertyChanged(param, param.getPropertyName(1)); + } - } + signedMode = APVTS.state.getProperty("mode").operator bool(); + isBypassed = APVTS.state.getProperty("bypass").operator bool(); +} + +std::unique_ptr BitDosAudioProcessor::createParam(const juce::String& name, const int min, const int max, const int def) +{ + return std::make_unique(juce::ParameterID{ name.toUpperCase(), 1 }, name, min, max, def); +} + +std::unique_ptr BitDosAudioProcessor::createParam(const juce::String &name, const float& min, const float& max, const float& inc, const float def) +{ + return std::make_unique(juce::ParameterID{ name.toUpperCase(), 1 }, name, juce::NormalisableRange(min, max, inc), def); } juce::AudioProcessorValueTreeState::ParameterLayout BitDosAudioProcessor::createParameters() { - std::vector> parameters; + std::vector> parameters(11); - for (int i = 8; i >= 1; i--) + for (int i = 7; i >= 0; i--) { - const juce::String bit = "Bit " + juce::String(i + 1); - - parameters.push_back(std::make_unique(juce::ParameterID{ bit.toUpperCase(), 1 }, - bit, 1, 3, 1)); + const char bitTxt[] = { 'B', 'i', 't', static_cast(i + 0x31), '\0' }; + parameters.operator[](i) = createParam(juce::String(bitTxt, 5), 1, 3, 1); } - parameters.push_back(std::make_unique(juce::ParameterID{ "PRE GAIN", 1 }, "Pre Gain", - juce::NormalisableRange(0.0f, 2.0f, 0.001f), 1.0f)); - - parameters.push_back(std::make_unique(juce::ParameterID{ "POST GAIN", 1 }, "Post Gain", - juce::NormalisableRange(0.0f, 2.0f, 0.001f), 1.0f)); - - parameters.push_back(std::make_unique(juce::ParameterID{ "BLEND", 1 }, "Blend", - juce::NormalisableRange(0.0f, 1.0f, 0.001f), 1.0f)); + parameters.operator[](8) = createParam("PreGain", 0.0f, 2.0f, 0.001f, 1.0f); + parameters.operator[](9) = createParam("PostGain", 0.0f, 2.0f, 0.001f, 1.0f); + parameters.operator[](10) = createParam("Blend", 0.0f, 2.0f, 0.001f, 1.0f); return { parameters.begin(), parameters.end() }; } -void BitDosAudioProcessor::valueTreePropertyChanged(juce::ValueTree&, const juce::Identifier&) +void BitDosAudioProcessor::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) { - paramsUpdated = true; -} + const char* changedParam = treeWhosePropertyHasChanged.getProperty(treeWhosePropertyHasChanged.getPropertyName(0)).toString().toRawUTF8(); + const juce::var paramVal = treeWhosePropertyHasChanged.getProperty(property); -void BitDosAudioProcessor::updateParams() -{ - readBits(); + if(std::strstr(changedParam, "BIT") != nullptr) + { + const int bit = changedParam[3] == ' ' ? changedParam[4] : changedParam[3]; + readBits(bit - 0x31, static_cast(paramVal.operator int())); + return; + } + + if(std::strstr(changedParam, "PRE") != nullptr) + { + preGain.store(paramVal.operator float()); + return; + } - preGain = APVTS.getRawParameterValue("PRE GAIN")->load(); - postGain = APVTS.getRawParameterValue("POST GAIN")->load(); - blend = APVTS.getRawParameterValue("BLEND")->load(); + if(std::strstr(changedParam, "POST") != nullptr) + { + postGain.store(paramVal.operator float()); + return; + } - paramsUpdated = false; + if(std::strstr(changedParam, "BLEND") != nullptr) + { + blend.store(paramVal.operator float()); + return; + } } -void BitDosAudioProcessor::readBits() +void BitDosAudioProcessor::readBits(const int bit, const BitSelect select) { - for (int i = 7; i >= 0; i--) - { - const juce::String bit = "BIT " + juce::String(i + 1); - - bitSet[i] = (BitSelect)(int)APVTS.getRawParameterValue(bit)->load(); + bitSet[bit] = select; - switch (bitSet[i]) - { - case (NORMAL_BIT): + switch (bitSet[bit]) + { + case (NORMAL_BIT): - resetBit(i); - break; + resetBit(bit); + break; - case (INVERT_BIT): + case (INVERT_BIT): - setBitInvert(i); - break; + setBitInvert(bit); + break; - case (HARD_0_BIT): + case (HARD_0_BIT): - setBitZeroed(i); - break; - } + setBitZeroed(bit); + break; } } diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 999e226..fcfa4ad 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -89,7 +89,7 @@ class BitDosAudioProcessor : public juce::AudioProcessor, void setBitSet(BitSelect select, int i) { - const juce::String bit = "BIT " + juce::String(i + 1); + const char bit[] = { 'B', 'I', 'T', static_cast(i + 0x31), '\0' }; APVTS.getParameter(bit)->beginChangeGesture(); APVTS.getParameterAsValue(bit).setValue(select); @@ -103,7 +103,6 @@ class BitDosAudioProcessor : public juce::AudioProcessor, void setSignedMode() { signedMode = !signedMode; - APVTS.state.setProperty("mode", (bool)signedMode, nullptr); } @@ -114,30 +113,26 @@ class BitDosAudioProcessor : public juce::AudioProcessor, void setPreGain(float gain) { - APVTS.getParameter("PRE GAIN")->beginChangeGesture(); - - if(gain >= 2.0) APVTS.getParameterAsValue("PRE GAIN").setValue(2.0f); - - else if (gain <= 0.0) APVTS.getParameterAsValue("PRE GAIN").setValue(0.0f); + APVTS.getParameter("PREGAIN")->beginChangeGesture(); - else APVTS.getParameterAsValue("PRE GAIN").setValue(gain); + if(gain >= 2.0) APVTS.getParameterAsValue("PREGAIN").setValue(2.0f); + else if (gain <= 0.0) APVTS.getParameterAsValue("PREGAIN").setValue(0.0f); + else APVTS.getParameterAsValue("PREGAIN").setValue(gain); - APVTS.getParameter("PRE GAIN")->endChangeGesture(); + APVTS.getParameter("PREGAIN")->endChangeGesture(); } std::atomic& getPostGain() { return postGain; } void setPostGain(float gain) { - APVTS.getParameter("POST GAIN")->beginChangeGesture(); - - if (gain >= 2.0) APVTS.getParameterAsValue("POST GAIN").setValue(2.0f); - - else if (gain <= 0.0) APVTS.getParameterAsValue("POST GAIN").setValue(0.0f); + APVTS.getParameter("POSTGAIN")->beginChangeGesture(); - else APVTS.getParameterAsValue("POST GAIN").setValue(gain); + if (gain >= 2.0) APVTS.getParameterAsValue("POSTGAIN").setValue(2.0f); + else if (gain <= 0.0) APVTS.getParameterAsValue("POSTGAIN").setValue(0.0f); + else APVTS.getParameterAsValue("POSTGAIN").setValue(gain); - APVTS.getParameter("POST GAIN")->endChangeGesture(); + APVTS.getParameter("POSTGAIN")->endChangeGesture(); } std::atomic& getBlend() { return blend; } @@ -146,9 +141,7 @@ class BitDosAudioProcessor : public juce::AudioProcessor, APVTS.getParameter("BLEND")->beginChangeGesture(); if (vol >= 1.0) APVTS.getParameterAsValue("BLEND").setValue(1.0f); - else if (vol <= 0.0) APVTS.getParameterAsValue("BLEND").setValue(0.0f); - else APVTS.getParameterAsValue("BLEND").setValue(vol); APVTS.getParameter("BLEND")->endChangeGesture(); @@ -168,24 +161,18 @@ class BitDosAudioProcessor : public juce::AudioProcessor, void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; - void updateParams(); - void readBits(); + std::unique_ptr createParam(const juce::String& name, const int min, const int max, const int def); + std::unique_ptr createParam(const juce::String &name, const float& min, const float& max, const float& inc, const float def); + + void readBits(const int bit, const BitSelect select); bool bitMode{ true }; float currentSample{ 0.0f }, muteCounter{ 0.0f }; - std::atomic preGain { 1.0f }; - std::atomic postGain{ 1.0f }; - std::atomic blend { 1.0f }; - - std::atomic signedMode{ false }; - std::atomic isBypassed{ false }; - std::atomic paramsUpdated{ false }; - - std::atomic bitInvert { 0 }; - std::atomic bitZeroed { 0 }; - std::atomic bitSample { 0 }; + std::atomic preGain { 1.0f }, postGain{ 1.0f }, blend { 1.0f }; + std::atomic signedMode{ false }, isBypassed{ false }, paramsUpdated{ false }; + std::atomic bitInvert { 0 }, bitZeroed { 0 }, bitSample { 0 }; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BitDosAudioProcessor)