kopia lustrzana https://github.com/jameshball/osci-render
It works
rodzic
f5d3f83a2f
commit
cad5bad853
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z" /></svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 222 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6,2H18V8H18V8L14,12L18,16V16H18V22H6V16H6V16L10,12L6,8V8H6V2M16,16.5L12,12.5L8,16.5V20H16V16.5M12,11.5L16,7.5V4H8V7.5L12,11.5M10,6H14V6.75L12,8.75L10,6.75V6Z" /></svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 237 B |
|
@ -26,7 +26,7 @@ private:
|
|||
std::unique_ptr<juce::FileChooser> chooser;
|
||||
juce::TextButton fileButton;
|
||||
juce::TextButton closeFileButton;
|
||||
SvgButton inputEnabled{"inputEnabled", juce::String(BinaryData::microphone_svg), "white", "red", audioProcessor.inputEnabled};
|
||||
SvgButton inputEnabled{"inputEnabled", juce::String(BinaryData::microphone_svg), juce::Colours::white, juce::Colours::red, audioProcessor.inputEnabled};
|
||||
juce::Label fileLabel;
|
||||
|
||||
juce::TextEditor fileName;
|
||||
|
|
|
@ -27,9 +27,9 @@ private:
|
|||
juce::TextButton resetRotation{"Reset Rotation"};
|
||||
juce::ToggleButton mouseRotate{"Rotate with Mouse (Esc to disable)"};
|
||||
|
||||
std::shared_ptr<SvgButton> fixedRotateX = std::make_shared<SvgButton>("fixedRotateX", juce::String(BinaryData::fixed_rotate_svg), "white", "red", audioProcessor.fixedRotateX);
|
||||
std::shared_ptr<SvgButton> fixedRotateY = std::make_shared<SvgButton>("fixedRotateY", juce::String(BinaryData::fixed_rotate_svg), "white", "red", audioProcessor.fixedRotateY);
|
||||
std::shared_ptr<SvgButton> fixedRotateZ = std::make_shared<SvgButton>("fixedRotateZ", juce::String(BinaryData::fixed_rotate_svg), "white", "red", audioProcessor.fixedRotateZ);
|
||||
std::shared_ptr<SvgButton> fixedRotateX = std::make_shared<SvgButton>("fixedRotateX", juce::String(BinaryData::fixed_rotate_svg), juce::Colours::white, juce::Colours::red, audioProcessor.fixedRotateX);
|
||||
std::shared_ptr<SvgButton> fixedRotateY = std::make_shared<SvgButton>("fixedRotateY", juce::String(BinaryData::fixed_rotate_svg), juce::Colours::white, juce::Colours::red, audioProcessor.fixedRotateY);
|
||||
std::shared_ptr<SvgButton> fixedRotateZ = std::make_shared<SvgButton>("fixedRotateZ", juce::String(BinaryData::fixed_rotate_svg), juce::Colours::white, juce::Colours::red, audioProcessor.fixedRotateZ);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ObjComponent)
|
||||
};
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include "DoubleTextBox.h"
|
||||
|
||||
//==============================================================================
|
||||
class AudioRecorder final : public juce::Thread {
|
||||
|
@ -116,6 +117,12 @@ public:
|
|||
consumer = audioProcessor.consumerRegister(buffer);
|
||||
audioProcessor.consumerRead(consumer);
|
||||
|
||||
if (nextSampleNum >= recordingLength * audioProcessor.currentSampleRate) {
|
||||
stop();
|
||||
stopCallback();
|
||||
continue;
|
||||
}
|
||||
|
||||
const juce::ScopedLock sl(writerLock);
|
||||
int numSamples = buffer.size() / 2;
|
||||
|
||||
|
@ -135,6 +142,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void setRecordLength(double recordLength) {
|
||||
recordingLength = recordLength;
|
||||
}
|
||||
|
||||
std::function<void()> stopCallback;
|
||||
|
||||
private:
|
||||
OscirenderAudioProcessor& audioProcessor;
|
||||
|
||||
|
@ -145,6 +158,8 @@ private:
|
|||
std::vector<float> buffer = std::vector<float>(2 << 12);
|
||||
std::shared_ptr<BufferConsumer> consumer;
|
||||
|
||||
double recordingLength = 99999999999.0;
|
||||
|
||||
juce::CriticalSection writerLock;
|
||||
std::atomic<juce::AudioFormatWriter::ThreadedWriter*> activeWriter { nullptr };
|
||||
};
|
||||
|
@ -177,10 +192,7 @@ public:
|
|||
: juce::jmax(30.0, thumbnail.getTotalLength());
|
||||
|
||||
auto thumbArea = getLocalBounds();
|
||||
thumbnail.drawChannels(g, thumbArea.reduced(2), 0.0, endTime, 2.0f);
|
||||
} else {
|
||||
g.setFont(14.0f);
|
||||
g.drawFittedText("(No file recorded)", getLocalBounds(), juce::Justification::centred, 2);
|
||||
thumbnail.drawChannels(g, thumbArea.reduced(2), 0.0, endTime, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,12 +216,35 @@ class AudioRecordingComponent final : public juce::Component {
|
|||
public:
|
||||
AudioRecordingComponent(OscirenderAudioProcessor& p) : audioProcessor(p) {
|
||||
addAndMakeVisible(recordButton);
|
||||
addAndMakeVisible(timedRecord);
|
||||
addAndMakeVisible(recordLength);
|
||||
|
||||
recordButton.setTooltip("Start recording audio to a WAV file. Press again to stop and save the recording.");
|
||||
timedRecord.setTooltip("Record for a set amount of time. When enabled, the recording will automatically stop once the time is reached.");
|
||||
|
||||
recordLength.setValue(1);
|
||||
|
||||
recordButton.onClick = [this] {
|
||||
if (recorder.isRecording())
|
||||
stopRecording();
|
||||
else
|
||||
if (recordButton.getToggleState()) {
|
||||
startRecording();
|
||||
} else {
|
||||
stopRecording();
|
||||
}
|
||||
};
|
||||
|
||||
timedRecord.onClick = [this] {
|
||||
if (timedRecord.getToggleState()) {
|
||||
addAndMakeVisible(recordLength);
|
||||
} else {
|
||||
removeChildComponent(&recordLength);
|
||||
}
|
||||
resized();
|
||||
};
|
||||
|
||||
recorder.stopCallback = [this] {
|
||||
juce::MessageManager::callAsync([this] {
|
||||
recordButton.setToggleState(false, juce::sendNotification);
|
||||
});
|
||||
};
|
||||
|
||||
addAndMakeVisible(recordingThumbnail);
|
||||
|
@ -217,8 +252,15 @@ public:
|
|||
}
|
||||
|
||||
void resized() override {
|
||||
double iconSize = 25;
|
||||
|
||||
auto area = getLocalBounds();
|
||||
recordButton.setBounds(area.removeFromLeft(80));
|
||||
recordButton.setBounds(area.removeFromLeft(iconSize).withSizeKeepingCentre(iconSize, iconSize));
|
||||
area.removeFromLeft(5);
|
||||
timedRecord.setBounds(area.removeFromLeft(iconSize).withSizeKeepingCentre(iconSize, iconSize));
|
||||
if (timedRecord.getToggleState()) {
|
||||
recordLength.setBounds(area.removeFromLeft(80).withSizeKeepingCentre(60, 25));
|
||||
}
|
||||
area.removeFromLeft(5);
|
||||
recordingThumbnail.setBounds(area);
|
||||
}
|
||||
|
@ -229,16 +271,22 @@ private:
|
|||
RecordingThumbnail recordingThumbnail;
|
||||
AudioRecorder recorder{ audioProcessor, recordingThumbnail.getAudioThumbnail() };
|
||||
|
||||
juce::TextButton recordButton{ "Record" };
|
||||
SvgButton recordButton{ "record", BinaryData::record_svg, juce::Colours::white, juce::Colours::red };
|
||||
juce::File lastRecording;
|
||||
juce::FileChooser chooser { "Output file...", juce::File::getCurrentWorkingDirectory().getChildFile("recording.wav"), "*.wav" };
|
||||
SvgButton timedRecord{ "timedRecord", BinaryData::timer_svg, juce::Colours::white, juce::Colours::red };
|
||||
DoubleTextBox recordLength{ 0, 60 * 60 * 24 };
|
||||
|
||||
void startRecording() {
|
||||
auto parentDir = juce::File::getSpecialLocation(juce::File::tempDirectory);
|
||||
|
||||
lastRecording = parentDir.getNonexistentChildFile("osci-render-recording", ".wav");
|
||||
if (timedRecord.getToggleState()) {
|
||||
recorder.setRecordLength(recordLength.getValue());
|
||||
} else {
|
||||
recorder.setRecordLength(99999999999.0);
|
||||
}
|
||||
recorder.startRecording(lastRecording);
|
||||
recordButton.setButtonText("Stop");
|
||||
|
||||
recordButton.setColour(juce::TextButton::buttonColourId, juce::Colours::red);
|
||||
recordButton.setColour(juce::TextButton::textColourOnId, juce::Colours::black);
|
||||
|
@ -247,8 +295,6 @@ private:
|
|||
void stopRecording() {
|
||||
recorder.stop();
|
||||
|
||||
recordButton.setButtonText("Record");
|
||||
|
||||
recordButton.setColour(juce::TextButton::buttonColourId, findColour(juce::TextButton::buttonColourId));
|
||||
recordButton.setColour(juce::TextButton::textColourOnId, findColour(juce::TextButton::textColourOnId));
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
|
||||
class DoubleTextBox : public juce::TextEditor {
|
||||
public:
|
||||
DoubleTextBox(double minValue, double maxValue) : minValue(minValue), maxValue(maxValue) {
|
||||
setText(juce::String(minValue, 2), false);
|
||||
setMultiLine(false);
|
||||
setJustification(juce::Justification::centred);
|
||||
setFont(juce::Font(15.0f, juce::Font::plain));
|
||||
onTextChange = [this]() {
|
||||
setText(getText(), false);
|
||||
};
|
||||
}
|
||||
|
||||
double getValue() {
|
||||
return getText().getDoubleValue();
|
||||
}
|
||||
|
||||
void setValue(double value, bool sendChangeMessage = true) {
|
||||
setText(juce::String(value, 2), sendChangeMessage);
|
||||
}
|
||||
|
||||
void setText(const juce::String& newText, bool sendChangeMessage = true) {
|
||||
// remove all non-digits
|
||||
juce::String text = newText.retainCharacters("0123456789.-");
|
||||
|
||||
// only keep first decimal point
|
||||
int firstDecimal = text.indexOfChar('.');
|
||||
if (firstDecimal != -1) {
|
||||
juce::String remainder = text.substring(firstDecimal + 1);
|
||||
remainder = remainder.retainCharacters("0123456789");
|
||||
text = text.substring(0, firstDecimal + 1) + remainder;
|
||||
}
|
||||
|
||||
// only keep negative sign at beginning
|
||||
if (text.contains("-")) {
|
||||
juce::String remainder = text.substring(1);
|
||||
remainder = remainder.retainCharacters("0123456789");
|
||||
text = text.substring(0, 1) + remainder;
|
||||
}
|
||||
|
||||
double value = text.getDoubleValue();
|
||||
if (value < minValue || value > maxValue) {
|
||||
text = juce::String(prevValue);
|
||||
} else {
|
||||
prevValue = value;
|
||||
}
|
||||
|
||||
juce::TextEditor::setText(text, sendChangeMessage);
|
||||
}
|
||||
|
||||
~DoubleTextBox() override {}
|
||||
|
||||
private:
|
||||
double minValue;
|
||||
double maxValue;
|
||||
double prevValue = minValue;
|
||||
};
|
|
@ -9,7 +9,7 @@ EffectComponent::EffectComponent(OscirenderAudioProcessor& p, Effect& effect, in
|
|||
|
||||
sidechainEnabled = effect.parameters[0]->sidechain != nullptr;
|
||||
if (sidechainEnabled) {
|
||||
sidechainButton = std::make_unique<SvgButton>(effect.parameters[0]->name, BinaryData::microphone_svg, "white", "red", effect.parameters[0]->sidechain);
|
||||
sidechainButton = std::make_unique<SvgButton>(effect.parameters[0]->name, BinaryData::microphone_svg, juce::Colours::white, juce::Colours::red, effect.parameters[0]->sidechain);
|
||||
sidechainButton->setTooltip("When enabled, the volume of the input audio controls the value of the slider, acting like a sidechain effect.");
|
||||
addAndMakeVisible(*sidechainButton);
|
||||
}
|
||||
|
|
|
@ -97,14 +97,14 @@ std::shared_ptr<juce::Component> EffectsListComponent::createComponent(EffectPar
|
|||
toggle = audioProcessor.perspectiveEffect->fixedRotateZ;
|
||||
axis = "Z";
|
||||
}
|
||||
std::shared_ptr<SvgButton> button = std::make_shared<SvgButton>(parameter->name, BinaryData::fixed_rotate_svg, "white", "red", toggle);
|
||||
std::shared_ptr<SvgButton> button = std::make_shared<SvgButton>(parameter->name, BinaryData::fixed_rotate_svg, juce::Colours::white, juce::Colours::red, toggle);
|
||||
button->setTooltip("Toggles whether the rotation around the " + axis + " axis is fixed, or changes according to the rotation speed.");
|
||||
button->onClick = [this, toggle] {
|
||||
toggle->setBoolValueNotifyingHost(!toggle->getBoolValue());
|
||||
};
|
||||
return button;
|
||||
} else if (parameter->paramID == "perspectiveStrength") {
|
||||
std::shared_ptr<SvgButton> button = std::make_shared<SvgButton>(parameter->name, BinaryData::pencil_svg, "white", "red");
|
||||
std::shared_ptr<SvgButton> button = std::make_shared<SvgButton>(parameter->name, BinaryData::pencil_svg, juce::Colours::white, juce::Colours::red);
|
||||
std::weak_ptr<SvgButton> weakButton = button;
|
||||
button->setEdgeIndent(5);
|
||||
button->setToggleState(editor.editingPerspective, juce::dontSendNotification);
|
||||
|
|
|
@ -3,19 +3,33 @@
|
|||
|
||||
class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParameter::Listener, public juce::AsyncUpdater {
|
||||
public:
|
||||
SvgButton(juce::String name, juce::String svg, juce::String colour, juce::String colourOn, BooleanParameter* toggle = nullptr) : juce::DrawableButton(name, juce::DrawableButton::ButtonStyle::ImageFitted), toggle(toggle) {
|
||||
SvgButton(juce::String name, juce::String svg, juce::Colour colour, juce::Colour colourOn, BooleanParameter* toggle = nullptr) : juce::DrawableButton(name, juce::DrawableButton::ButtonStyle::ImageFitted), toggle(toggle) {
|
||||
auto doc = juce::XmlDocument::parse(svg);
|
||||
|
||||
changeSvgColour(doc.get(), colour);
|
||||
normalImage = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colour.withBrightness(0.7f));
|
||||
overImage = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colour.withBrightness(0.5f));
|
||||
downImage = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colour.withBrightness(0.3f));
|
||||
disabledImage = juce::Drawable::createFromSVG(*doc);
|
||||
|
||||
changeSvgColour(doc.get(), colourOn);
|
||||
normalImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.7f));
|
||||
overImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.5f));
|
||||
downImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
changeSvgColour(doc.get(), colourOn.withBrightness(0.3f));
|
||||
disabledImageOn = juce::Drawable::createFromSVG(*doc);
|
||||
|
||||
getLookAndFeel().setColour(juce::DrawableButton::backgroundOnColourId, juce::Colours::transparentWhite);
|
||||
|
||||
if (colour != colourOn) {
|
||||
setClickingTogglesState(true);
|
||||
}
|
||||
setImages(normalImage.get(), nullptr, nullptr, nullptr, normalImageOn.get());
|
||||
setImages(normalImage.get(), overImage.get(), downImage.get(), disabledImage.get(), normalImageOn.get(), overImageOn.get(), downImageOn.get(), disabledImageOn.get());
|
||||
|
||||
if (toggle != nullptr) {
|
||||
toggle->addListener(this);
|
||||
|
@ -23,7 +37,7 @@ class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParame
|
|||
}
|
||||
}
|
||||
|
||||
SvgButton(juce::String name, juce::String svg, juce::String colour) : SvgButton(name, svg, colour, colour) {}
|
||||
SvgButton(juce::String name, juce::String svg, juce::Colour colour) : SvgButton(name, svg, colour, colour) {}
|
||||
|
||||
~SvgButton() override {
|
||||
if (toggle != nullptr) {
|
||||
|
@ -42,12 +56,20 @@ class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParame
|
|||
}
|
||||
private:
|
||||
std::unique_ptr<juce::Drawable> normalImage;
|
||||
std::unique_ptr<juce::Drawable> overImage;
|
||||
std::unique_ptr<juce::Drawable> downImage;
|
||||
std::unique_ptr<juce::Drawable> disabledImage;
|
||||
|
||||
std::unique_ptr<juce::Drawable> normalImageOn;
|
||||
std::unique_ptr<juce::Drawable> overImageOn;
|
||||
std::unique_ptr<juce::Drawable> downImageOn;
|
||||
std::unique_ptr<juce::Drawable> disabledImageOn;
|
||||
|
||||
BooleanParameter* toggle;
|
||||
|
||||
void changeSvgColour(juce::XmlElement* xml, juce::String colour) {
|
||||
void changeSvgColour(juce::XmlElement* xml, juce::Colour colour) {
|
||||
forEachXmlChildElement(*xml, xmlnode) {
|
||||
xmlnode->setAttribute("fill", colour);
|
||||
xmlnode->setAttribute("fill", '#' + colour.toDisplayString(false));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
<FILE id="PxYKbt" name="microphone.svg" compile="0" resource="1" file="Resources/svg/microphone.svg"/>
|
||||
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
|
||||
<FILE id="D2AI1b" name="pencil.svg" compile="0" resource="1" file="Resources/svg/pencil.svg"/>
|
||||
<FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/>
|
||||
<FILE id="rXjNlx" name="threshold.svg" compile="0" resource="1" file="Resources/svg/threshold.svg"/>
|
||||
<FILE id="rFYmV8" name="timer.svg" compile="0" resource="1" file="Resources/svg/timer.svg"/>
|
||||
<FILE id="qC6QiP" name="volume.svg" compile="0" resource="1" file="Resources/svg/volume.svg"/>
|
||||
</GROUP>
|
||||
<GROUP id="{F8A3D32C-4187-9A2F-5D78-040259957E9B}" name="text">
|
||||
|
@ -106,6 +108,7 @@
|
|||
<FILE id="kUinTt" name="ComponentList.cpp" compile="1" resource="0"
|
||||
file="Source/components/ComponentList.cpp"/>
|
||||
<FILE id="HGTPEW" name="ComponentList.h" compile="0" resource="0" file="Source/components/ComponentList.h"/>
|
||||
<FILE id="IvySRY" name="DoubleTextBox.h" compile="0" resource="0" file="Source/components/DoubleTextBox.h"/>
|
||||
<FILE id="poPVxL" name="DraggableListBox.cpp" compile="1" resource="0"
|
||||
file="Source/components/DraggableListBox.cpp"/>
|
||||
<FILE id="Y9NEGn" name="DraggableListBox.h" compile="0" resource="0"
|
||||
|
|
Ładowanie…
Reference in New Issue