kopia lustrzana https://github.com/jameshball/osci-render
Fix several bugs, add audio player at bottom for sosci
rodzic
ed027bbfc4
commit
dd3d051793
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M10,16.5L16,12L10,7.5V16.5Z" /></svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 273 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6,5.75L10.25,10H7V16H13.5L15.5,18H7A2,2 0 0,1 5,16V10H1.75L6,5.75M18,18.25L13.75,14H17V8H10.5L8.5,6H17A2,2 0 0,1 19,8V14H22.25L18,18.25Z" /></svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 216 B |
|
@ -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,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4M9,9V15H15V9" /></svg>
|
Po Szerokość: | Wysokość: | Rozmiar: 257 B |
|
@ -44,7 +44,7 @@ CommonPluginEditor::CommonPluginEditor(CommonAudioProcessor& p, juce::String app
|
||||||
|
|
||||||
recordingSettings.setLookAndFeel(&getLookAndFeel());
|
recordingSettings.setLookAndFeel(&getLookAndFeel());
|
||||||
recordingSettings.setSize(300, 200);
|
recordingSettings.setSize(300, 200);
|
||||||
recordingSettingsWindow.centreWithSize(300, 200);
|
recordingSettingsWindow.centreWithSize(300, 230);
|
||||||
#if JUCE_WINDOWS
|
#if JUCE_WINDOWS
|
||||||
// if not standalone, use native title bar for compatibility with DAWs
|
// if not standalone, use native title bar for compatibility with DAWs
|
||||||
recordingSettingsWindow.setUsingNativeTitleBar(processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone);
|
recordingSettingsWindow.setUsingNativeTitleBar(processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone);
|
||||||
|
|
|
@ -52,15 +52,13 @@ public:
|
||||||
RecordingSettings recordingSettings = RecordingSettings(audioProcessor.recordingParameters);
|
RecordingSettings recordingSettings = RecordingSettings(audioProcessor.recordingParameters);
|
||||||
SettingsWindow recordingSettingsWindow = SettingsWindow("Recording Settings", recordingSettings);
|
SettingsWindow recordingSettingsWindow = SettingsWindow("Recording Settings", recordingSettings);
|
||||||
VisualiserComponent visualiser{
|
VisualiserComponent visualiser{
|
||||||
audioProcessor.lastOpenedDirectory,
|
audioProcessor,
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
sharedTextureManager,
|
sharedTextureManager,
|
||||||
#endif
|
#endif
|
||||||
applicationFolder.getChildFile(ffmpegFileName),
|
applicationFolder.getChildFile(ffmpegFileName),
|
||||||
audioProcessor.haltRecording,
|
|
||||||
audioProcessor.threadManager,
|
|
||||||
visualiserSettings,
|
visualiserSettings,
|
||||||
audioProcessor.recordingParameters,
|
recordingSettings,
|
||||||
nullptr,
|
nullptr,
|
||||||
appName == "sosci"
|
appName == "sosci"
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "CommonPluginProcessor.h"
|
#include "CommonPluginProcessor.h"
|
||||||
#include "CommonPluginEditor.h"
|
#include "CommonPluginEditor.h"
|
||||||
#include "audio/EffectParameter.h"
|
#include "audio/EffectParameter.h"
|
||||||
|
#include "components/AudioPlayerComponent.h"
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
CommonAudioProcessor::CommonAudioProcessor()
|
CommonAudioProcessor::CommonAudioProcessor()
|
||||||
|
@ -182,3 +183,36 @@ bool CommonAudioProcessor::hasEditor() const {
|
||||||
double CommonAudioProcessor::getSampleRate() {
|
double CommonAudioProcessor::getSampleRate() {
|
||||||
return currentSampleRate;
|
return currentSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommonAudioProcessor::loadAudioFile(const juce::File& file) {
|
||||||
|
auto stream = std::make_unique<juce::FileInputStream>(file);
|
||||||
|
if (stream->openedOk()) {
|
||||||
|
juce::SpinLock::ScopedLockType lock(wavParserLock);
|
||||||
|
wavParser = std::make_shared<WavParser>(*this, std::move(stream));
|
||||||
|
|
||||||
|
juce::SpinLock::ScopedLockType lock2(audioPlayerListenersLock);
|
||||||
|
for (auto listener : audioPlayerListeners) {
|
||||||
|
listener->parserChanged(wavParser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonAudioProcessor::stopAudioFile() {
|
||||||
|
juce::SpinLock::ScopedLockType lock(wavParserLock);
|
||||||
|
wavParser = nullptr;
|
||||||
|
|
||||||
|
juce::SpinLock::ScopedLockType lock2(audioPlayerListenersLock);
|
||||||
|
for (auto listener : audioPlayerListeners) {
|
||||||
|
listener->parserChanged(wavParser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonAudioProcessor::addAudioPlayerListener(AudioPlayerListener* listener) {
|
||||||
|
juce::SpinLock::ScopedLockType lock(audioPlayerListenersLock);
|
||||||
|
audioPlayerListeners.push_back(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonAudioProcessor::removeAudioPlayerListener(AudioPlayerListener* listener) {
|
||||||
|
juce::SpinLock::ScopedLockType lock(audioPlayerListenersLock);
|
||||||
|
audioPlayerListeners.erase(std::remove(audioPlayerListeners.begin(), audioPlayerListeners.end(), listener), audioPlayerListeners.end());
|
||||||
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
#include "visualiser/VisualiserSettings.h"
|
#include "visualiser/VisualiserSettings.h"
|
||||||
#include "visualiser/RecordingSettings.h"
|
#include "visualiser/RecordingSettings.h"
|
||||||
#include "audio/Effect.h"
|
#include "audio/Effect.h"
|
||||||
|
#include "wav/WavParser.h"
|
||||||
|
|
||||||
//==============================================================================
|
|
||||||
/**
|
class AudioPlayerListener;
|
||||||
*/
|
|
||||||
class CommonAudioProcessor : public juce::AudioProcessor, public SampleRateManager
|
class CommonAudioProcessor : public juce::AudioProcessor, public SampleRateManager
|
||||||
#if JucePlugin_Enable_ARA
|
#if JucePlugin_Enable_ARA
|
||||||
, public juce::AudioProcessorARAExtension
|
, public juce::AudioProcessorARAExtension
|
||||||
|
@ -54,6 +54,13 @@ public:
|
||||||
const juce::String getProgramName(int index) override;
|
const juce::String getProgramName(int index) override;
|
||||||
void changeProgramName(int index, const juce::String& newName) override;
|
void changeProgramName(int index, const juce::String& newName) override;
|
||||||
double getSampleRate() override;
|
double getSampleRate() override;
|
||||||
|
void loadAudioFile(const juce::File& file);
|
||||||
|
void stopAudioFile();
|
||||||
|
void addAudioPlayerListener(AudioPlayerListener* listener);
|
||||||
|
void removeAudioPlayerListener(AudioPlayerListener* listener);
|
||||||
|
|
||||||
|
juce::SpinLock audioPlayerListenersLock;
|
||||||
|
std::vector<AudioPlayerListener*> audioPlayerListeners;
|
||||||
|
|
||||||
std::atomic<double> volume = 1.0;
|
std::atomic<double> volume = 1.0;
|
||||||
std::atomic<double> threshold = 1.0;
|
std::atomic<double> threshold = 1.0;
|
||||||
|
@ -82,6 +89,9 @@ public:
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
juce::SpinLock wavParserLock;
|
||||||
|
std::shared_ptr<WavParser> wavParser;
|
||||||
|
|
||||||
std::atomic<double> currentSampleRate = 0.0;
|
std::atomic<double> currentSampleRate = 0.0;
|
||||||
juce::SpinLock effectsLock;
|
juce::SpinLock effectsLock;
|
||||||
VisualiserParameters visualiserParameters;
|
VisualiserParameters visualiserParameters;
|
||||||
|
|
|
@ -30,5 +30,8 @@ void SosciPluginEditor::resized() {
|
||||||
visualiserSettings.setSize(settingsArea.getWidth(), 550);
|
visualiserSettings.setSize(settingsArea.getWidth(), 550);
|
||||||
visualiserSettingsWrapper.setBounds(settingsArea);
|
visualiserSettingsWrapper.setBounds(settingsArea);
|
||||||
|
|
||||||
|
if (area.getWidth() < 10 || area.getHeight() < 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
visualiser.setBounds(area);
|
visualiser.setBounds(area);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ void SosciAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::M
|
||||||
auto inputArray = input.getArrayOfWritePointers();
|
auto inputArray = input.getArrayOfWritePointers();
|
||||||
auto outputArray = output.getArrayOfWritePointers();
|
auto outputArray = output.getArrayOfWritePointers();
|
||||||
|
|
||||||
juce::CriticalSection::ScopedLockType lock2(wavParserLock);
|
juce::SpinLock::ScopedLockType lock2(wavParserLock);
|
||||||
bool readingFromWav = wavParser != nullptr;
|
bool readingFromWav = wavParser != nullptr;
|
||||||
|
|
||||||
for (int sample = 0; sample < input.getNumSamples(); ++sample) {
|
for (int sample = 0; sample < input.getNumSamples(); ++sample) {
|
||||||
|
@ -175,19 +175,6 @@ void SosciAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SosciAudioProcessor::loadAudioFile(const juce::File& file) {
|
|
||||||
auto stream = std::make_unique<juce::FileInputStream>(file);
|
|
||||||
if (stream->openedOk()) {
|
|
||||||
juce::CriticalSection::ScopedLockType lock(wavParserLock);
|
|
||||||
wavParser = std::make_unique<WavParser>(*this, std::move(stream));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SosciAudioProcessor::stopAudioFile() {
|
|
||||||
juce::CriticalSection::ScopedLockType lock(wavParserLock);
|
|
||||||
wavParser = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
juce::AudioProcessorEditor* SosciAudioProcessor::createEditor() {
|
juce::AudioProcessorEditor* SosciAudioProcessor::createEditor() {
|
||||||
auto editor = new SosciPluginEditor(*this);
|
auto editor = new SosciPluginEditor(*this);
|
||||||
return editor;
|
return editor;
|
||||||
|
|
|
@ -30,16 +30,9 @@ public:
|
||||||
|
|
||||||
void getStateInformation(juce::MemoryBlock& destData) override;
|
void getStateInformation(juce::MemoryBlock& destData) override;
|
||||||
void setStateInformation(const void* data, int sizeInBytes) override;
|
void setStateInformation(const void* data, int sizeInBytes) override;
|
||||||
|
|
||||||
void loadAudioFile(const juce::File& file);
|
|
||||||
void stopAudioFile();
|
|
||||||
|
|
||||||
juce::AudioProcessorEditor* createEditor() override;
|
juce::AudioProcessorEditor* createEditor() override;
|
||||||
|
|
||||||
private:
|
|
||||||
juce::CriticalSection wavParserLock;
|
|
||||||
std::unique_ptr<WavParser> wavParser;
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SosciAudioProcessor)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SosciAudioProcessor)
|
||||||
};
|
};
|
||||||
|
|
|
@ -129,8 +129,6 @@ private:
|
||||||
// value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range
|
// value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range
|
||||||
std::atomic<float> value = 0.0;
|
std::atomic<float> value = 0.0;
|
||||||
juce::String label;
|
juce::String label;
|
||||||
|
|
||||||
JUCE_HEAVYWEIGHT_LEAK_DETECTOR(FloatParameter)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IntParameter : public juce::AudioProcessorParameterWithID {
|
class IntParameter : public juce::AudioProcessorParameterWithID {
|
||||||
|
@ -253,8 +251,6 @@ public:
|
||||||
private:
|
private:
|
||||||
// value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range
|
// value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range
|
||||||
std::atomic<int> value = 0;
|
std::atomic<int> value = 0;
|
||||||
|
|
||||||
JUCE_HEAVYWEIGHT_LEAK_DETECTOR(IntParameter)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LfoType : int {
|
enum class LfoType : int {
|
||||||
|
@ -404,6 +400,4 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectParameter(juce::String name, juce::String description, juce::String id, int versionHint, float value, float min, float max, float step = 0.01, bool smoothValueChange = true) : FloatParameter(name, id, versionHint, value, min, max, step), smoothValueChange(smoothValueChange), description(description) {}
|
EffectParameter(juce::String name, juce::String description, juce::String id, int versionHint, float value, float min, float max, float step = 0.01, bool smoothValueChange = true) : FloatParameter(name, id, versionHint, value, min, max, step), smoothValueChange(smoothValueChange), description(description) {}
|
||||||
|
|
||||||
JUCE_HEAVYWEIGHT_LEAK_DETECTOR(EffectParameter)
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
#include "AudioPlayerComponent.h"
|
||||||
|
#include "../CommonPluginProcessor.h"
|
||||||
|
|
||||||
|
AudioPlayerComponent::AudioPlayerComponent(CommonAudioProcessor& processor) : audioProcessor(processor) {
|
||||||
|
setOpaque(false);
|
||||||
|
|
||||||
|
audioProcessor.addAudioPlayerListener(this);
|
||||||
|
|
||||||
|
parser = audioProcessor.wavParser;
|
||||||
|
|
||||||
|
addAndMakeVisible(slider);
|
||||||
|
slider.setSliderStyle(juce::Slider::SliderStyle::LinearHorizontal);
|
||||||
|
slider.setTextBoxStyle(juce::Slider::NoTextBox, true, 0, 0);
|
||||||
|
slider.setOpaque(false);
|
||||||
|
slider.setRange(0, 1, 0.001);
|
||||||
|
slider.setLookAndFeel(&timelineLookAndFeel);
|
||||||
|
slider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black);
|
||||||
|
|
||||||
|
slider.onValueChange = [this]() {
|
||||||
|
juce::SpinLock::ScopedLockType sl(audioProcessor.wavParserLock);
|
||||||
|
|
||||||
|
if (parser != nullptr) {
|
||||||
|
parser->setProgress(slider.getValue());
|
||||||
|
} else {
|
||||||
|
slider.setValue(0, juce::dontSendNotification);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addChildComponent(playButton);
|
||||||
|
addChildComponent(pauseButton);
|
||||||
|
|
||||||
|
playButton.setTooltip("Play audio file");
|
||||||
|
pauseButton.setTooltip("Pause audio file");
|
||||||
|
|
||||||
|
repeatButton.setToggleState(true, juce::dontSendNotification);
|
||||||
|
|
||||||
|
playButton.onClick = [this]() {
|
||||||
|
juce::SpinLock::ScopedLockType sl(audioProcessor.wavParserLock);
|
||||||
|
|
||||||
|
if (parser != nullptr) {
|
||||||
|
parser->setPaused(false);
|
||||||
|
playButton.setVisible(false);
|
||||||
|
pauseButton.setVisible(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pauseButton.onClick = [this]() {
|
||||||
|
juce::SpinLock::ScopedLockType sl(audioProcessor.wavParserLock);
|
||||||
|
|
||||||
|
if (parser != nullptr) {
|
||||||
|
parser->setPaused(true);
|
||||||
|
playButton.setVisible(true);
|
||||||
|
pauseButton.setVisible(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addAndMakeVisible(repeatButton);
|
||||||
|
|
||||||
|
repeatButton.setTooltip("Repeat audio file once it finishes playing");
|
||||||
|
|
||||||
|
repeatButton.onClick = [this]() {
|
||||||
|
juce::SpinLock::ScopedLockType sl(audioProcessor.wavParserLock);
|
||||||
|
|
||||||
|
if (parser != nullptr) {
|
||||||
|
parser->setLooping(repeatButton.getToggleState());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addAndMakeVisible(stopButton);
|
||||||
|
|
||||||
|
stopButton.setTooltip("Stop and close audio file");
|
||||||
|
|
||||||
|
stopButton.onClick = [this]() {
|
||||||
|
audioProcessor.stopAudioFile();
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
juce::SpinLock::ScopedLockType sl(audioProcessor.wavParserLock);
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioPlayerComponent::~AudioPlayerComponent() {
|
||||||
|
audioProcessor.removeAudioPlayerListener(this);
|
||||||
|
juce::SpinLock::ScopedLockType sl(audioProcessor.wavParserLock);
|
||||||
|
if (parser != nullptr) {
|
||||||
|
parser->onProgress = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// must hold lock
|
||||||
|
void AudioPlayerComponent::setup() {
|
||||||
|
if (parser != nullptr) {
|
||||||
|
slider.setVisible(true);
|
||||||
|
repeatButton.setVisible(true);
|
||||||
|
stopButton.setVisible(true);
|
||||||
|
parser->onProgress = [this](double progress) {
|
||||||
|
juce::WeakReference<AudioPlayerComponent> weakRef(this);
|
||||||
|
juce::MessageManager::callAsync([this, progress, weakRef]() {
|
||||||
|
if (weakRef) {
|
||||||
|
slider.setValue(progress, juce::dontSendNotification);
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
playButton.setVisible(parser->isPaused());
|
||||||
|
pauseButton.setVisible(!parser->isPaused());
|
||||||
|
parser->setLooping(repeatButton.getToggleState());
|
||||||
|
} else {
|
||||||
|
slider.setVisible(false);
|
||||||
|
repeatButton.setVisible(false);
|
||||||
|
stopButton.setVisible(false);
|
||||||
|
slider.setValue(0);
|
||||||
|
playButton.setVisible(false);
|
||||||
|
pauseButton.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
parserWasNull = parser == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioPlayerComponent::setPaused(bool paused) {
|
||||||
|
if (paused) {
|
||||||
|
pauseButton.triggerClick();
|
||||||
|
} else {
|
||||||
|
playButton.triggerClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioPlayerComponent::parserChanged(std::shared_ptr<WavParser> parser) {
|
||||||
|
this->parser = parser;
|
||||||
|
setup();
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioPlayerComponent::resized() {
|
||||||
|
auto r = getLocalBounds();
|
||||||
|
|
||||||
|
auto playPauseBounds = r.removeFromLeft(25);
|
||||||
|
playButton.setBounds(playPauseBounds);
|
||||||
|
pauseButton.setBounds(playPauseBounds);
|
||||||
|
stopButton.setBounds(r.removeFromLeft(25));
|
||||||
|
|
||||||
|
repeatButton.setBounds(r.removeFromRight(25));
|
||||||
|
|
||||||
|
slider.setBounds(r);
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <JuceHeader.h>
|
||||||
|
#include "../CommonPluginProcessor.h"
|
||||||
|
#include "../LookAndFeel.h"
|
||||||
|
#include "../wav/WavParser.h"
|
||||||
|
|
||||||
|
class TimelineLookAndFeel : public OscirenderLookAndFeel {
|
||||||
|
public:
|
||||||
|
TimelineLookAndFeel() {}
|
||||||
|
|
||||||
|
void drawLinearSlider(juce::Graphics& g, int x, int y, int width, int height, float sliderPos, float minSliderPos, float maxSliderPos, const juce::Slider::SliderStyle style, juce::Slider& slider) override {
|
||||||
|
auto trackWidth = juce::jmin (6.0f, slider.isHorizontal() ? (float) height * 0.25f : (float) width * 0.25f);
|
||||||
|
|
||||||
|
juce::Point<float> startPoint (slider.isHorizontal() ? (float) x : (float) x + (float) width * 0.5f,
|
||||||
|
slider.isHorizontal() ? (float) y + (float) height * 0.5f : (float) (height + y));
|
||||||
|
|
||||||
|
juce::Point<float> endPoint (slider.isHorizontal() ? (float) (width + x) : startPoint.x,
|
||||||
|
slider.isHorizontal() ? startPoint.y : (float) y);
|
||||||
|
|
||||||
|
juce::Path backgroundTrack;
|
||||||
|
backgroundTrack.startNewSubPath (startPoint);
|
||||||
|
backgroundTrack.lineTo (endPoint);
|
||||||
|
g.setColour (slider.findColour (juce::Slider::backgroundColourId));
|
||||||
|
g.strokePath (backgroundTrack, { trackWidth, juce::PathStrokeType::curved, juce::PathStrokeType::rounded });
|
||||||
|
|
||||||
|
juce::Path valueTrack;
|
||||||
|
juce::Point<float> minPoint, maxPoint, thumbPoint;
|
||||||
|
|
||||||
|
auto kx = slider.isHorizontal() ? sliderPos : ((float) x + (float) width * 0.5f);
|
||||||
|
auto ky = slider.isHorizontal() ? ((float) y + (float) height * 0.5f) : sliderPos;
|
||||||
|
|
||||||
|
minPoint = startPoint;
|
||||||
|
maxPoint = { kx, ky };
|
||||||
|
|
||||||
|
auto thumbWidth = getSliderThumbRadius (slider);
|
||||||
|
|
||||||
|
valueTrack.startNewSubPath (minPoint);
|
||||||
|
valueTrack.lineTo (maxPoint);
|
||||||
|
g.setColour (slider.findColour (juce::Slider::trackColourId));
|
||||||
|
g.strokePath (valueTrack, { trackWidth, juce::PathStrokeType::curved, juce::PathStrokeType::rounded });
|
||||||
|
|
||||||
|
g.setColour (slider.findColour (juce::Slider::thumbColourId));
|
||||||
|
g.fillRect (juce::Rectangle<float> (thumbWidth / 2, 1.5 * thumbWidth).withCentre (maxPoint));
|
||||||
|
|
||||||
|
g.setColour(slider.findColour(sliderThumbOutlineColourId).withAlpha(slider.isEnabled() ? 1.0f : 0.5f));
|
||||||
|
g.drawRect(juce::Rectangle<float>(thumbWidth / 2, 1.5 * thumbWidth).withCentre(maxPoint));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioPlayerListener {
|
||||||
|
public:
|
||||||
|
virtual void parserChanged(std::shared_ptr<WavParser> parser) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommonAudioProcessor;
|
||||||
|
class AudioPlayerComponent : public juce::Component, public AudioPlayerListener {
|
||||||
|
public:
|
||||||
|
AudioPlayerComponent(CommonAudioProcessor& processor);
|
||||||
|
~AudioPlayerComponent() override;
|
||||||
|
|
||||||
|
void resized() override;
|
||||||
|
void setup();
|
||||||
|
void parserChanged(std::shared_ptr<WavParser> parser) override;
|
||||||
|
void setPaused(bool paused);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CommonAudioProcessor& audioProcessor;
|
||||||
|
|
||||||
|
bool parserWasNull = true;
|
||||||
|
std::shared_ptr<WavParser> parser;
|
||||||
|
|
||||||
|
TimelineLookAndFeel timelineLookAndFeel;
|
||||||
|
|
||||||
|
SvgButton playButton{ "Play", BinaryData::play_svg, juce::Colours::white, juce::Colours::white};
|
||||||
|
SvgButton pauseButton{ "Pause", BinaryData::pause_svg, juce::Colours::white, juce::Colours::white };
|
||||||
|
SvgButton repeatButton{ "Repeat", BinaryData::repeat_svg, juce::Colours::white, Colours::accentColor };
|
||||||
|
SvgButton stopButton{ "Stop", BinaryData::stop_svg, juce::Colours::white, juce::Colours::white };
|
||||||
|
juce::Slider slider;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioPlayerComponent)
|
||||||
|
JUCE_DECLARE_WEAK_REFERENCEABLE(AudioPlayerComponent)
|
||||||
|
};
|
|
@ -37,18 +37,16 @@ SosciMainMenuBarModel::SosciMainMenuBarModel(SosciPluginEditor& e, SosciAudioPro
|
||||||
};
|
};
|
||||||
|
|
||||||
addMenuItem(0, "Open Audio File", [&]() {
|
addMenuItem(0, "Open Audio File", [&]() {
|
||||||
fileChooser = std::make_unique<juce::FileChooser>("Open Audio File", processor.lastOpenedDirectory, "*.wav;*.aiff;*.flac;*.ogg");
|
fileChooser = std::make_unique<juce::FileChooser>("Open Audio File", processor.lastOpenedDirectory, "*.wav;*.aiff;*.flac;*.ogg;*.mp3");
|
||||||
auto flags = juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles;
|
auto flags = juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectFiles;
|
||||||
fileChooser->launchAsync(flags, [&](const juce::FileChooser& chooser) {
|
fileChooser->launchAsync(flags, [&](const juce::FileChooser& chooser) {
|
||||||
auto file = chooser.getResult();
|
auto file = chooser.getResult();
|
||||||
if (file != juce::File()) {
|
if (file != juce::File()) {
|
||||||
processor.loadAudioFile(file);
|
processor.loadAudioFile(file);
|
||||||
|
processor.lastOpenedDirectory = file.getParentDirectory();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
addMenuItem(0, "Stop Audio File", [&]() {
|
|
||||||
processor.stopAudioFile();
|
|
||||||
});
|
|
||||||
addMenuItem(0, "Open Project", [&]() { editor.openProject(); });
|
addMenuItem(0, "Open Project", [&]() { editor.openProject(); });
|
||||||
addMenuItem(0, "Save Project", [&]() { editor.saveProject(); });
|
addMenuItem(0, "Save Project", [&]() { editor.saveProject(); });
|
||||||
addMenuItem(0, "Save Project As", [&]() { editor.saveProjectAs(); });
|
addMenuItem(0, "Save Project As", [&]() { editor.saveProjectAs(); });
|
||||||
|
|
|
@ -38,24 +38,6 @@ public:
|
||||||
|
|
||||||
juce::String compressionPreset = "fast";
|
juce::String compressionPreset = "fast";
|
||||||
|
|
||||||
int getCRF() {
|
|
||||||
double quality = juce::jlimit(0.0, 1.0, qualityEffect.getValue());
|
|
||||||
// mapping to 0-51 for ffmpeg's crf value
|
|
||||||
return 51 * (1.0 - quality) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool recordingVideo() {
|
|
||||||
return recordVideo.getBoolValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool recordingAudio() {
|
|
||||||
return recordAudio.getBoolValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
juce::String getCompressionPreset() {
|
|
||||||
return compressionPreset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void save(juce::XmlElement* xml) {
|
void save(juce::XmlElement* xml) {
|
||||||
auto settingsXml = xml->createNewChildElement("recordingSettings");
|
auto settingsXml = xml->createNewChildElement("recordingSettings");
|
||||||
recordAudio.save(settingsXml->createNewChildElement("recordAudio"));
|
recordAudio.save(settingsXml->createNewChildElement("recordAudio"));
|
||||||
|
@ -94,6 +76,24 @@ public:
|
||||||
|
|
||||||
void resized() override;
|
void resized() override;
|
||||||
|
|
||||||
|
int getCRF() {
|
||||||
|
double quality = juce::jlimit(0.0, 1.0, parameters.qualityEffect.getValue());
|
||||||
|
// mapping to 0-51 for ffmpeg's crf value
|
||||||
|
return 51 * (1.0 - quality) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recordingVideo() {
|
||||||
|
return parameters.recordVideo.getBoolValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recordingAudio() {
|
||||||
|
return parameters.recordAudio.getBoolValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
juce::String getCompressionPreset() {
|
||||||
|
return parameters.compressionPreset;
|
||||||
|
}
|
||||||
|
|
||||||
RecordingParameters& parameters;
|
RecordingParameters& parameters;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "../LookAndFeel.h"
|
#include "../LookAndFeel.h"
|
||||||
#include "VisualiserComponent.h"
|
#include "VisualiserComponent.h"
|
||||||
|
#include "../CommonPluginProcessor.h"
|
||||||
|
|
||||||
#include "BlurFragmentShader.glsl"
|
#include "BlurFragmentShader.glsl"
|
||||||
#include "BlurVertexShader.glsl"
|
#include "BlurVertexShader.glsl"
|
||||||
#include "WideBlurFragmentShader.glsl"
|
#include "WideBlurFragmentShader.glsl"
|
||||||
|
@ -16,28 +18,24 @@
|
||||||
#include "TexturedVertexShader.glsl"
|
#include "TexturedVertexShader.glsl"
|
||||||
|
|
||||||
VisualiserComponent::VisualiserComponent(
|
VisualiserComponent::VisualiserComponent(
|
||||||
juce::File& lastOpenedDirectory,
|
CommonAudioProcessor& processor,
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
SharedTextureManager& sharedTextureManager,
|
SharedTextureManager& sharedTextureManager,
|
||||||
#endif
|
#endif
|
||||||
juce::File ffmpegFile,
|
juce::File ffmpegFile,
|
||||||
std::function<void()>& haltRecording,
|
|
||||||
AudioBackgroundThreadManager& threadManager,
|
|
||||||
VisualiserSettings& settings,
|
VisualiserSettings& settings,
|
||||||
RecordingParameters& recordingParameters,
|
RecordingSettings& recordingSettings,
|
||||||
VisualiserComponent* parent,
|
VisualiserComponent* parent,
|
||||||
bool visualiserOnly
|
bool visualiserOnly
|
||||||
) : lastOpenedDirectory(lastOpenedDirectory),
|
) : audioProcessor(processor),
|
||||||
ffmpegFile(ffmpegFile),
|
ffmpegFile(ffmpegFile),
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
sharedTextureManager(sharedTextureManager),
|
sharedTextureManager(sharedTextureManager),
|
||||||
#endif
|
#endif
|
||||||
haltRecording(haltRecording),
|
|
||||||
settings(settings),
|
settings(settings),
|
||||||
recordingParameters(recordingParameters),
|
recordingSettings(recordingSettings),
|
||||||
threadManager(threadManager),
|
|
||||||
visualiserOnly(visualiserOnly),
|
visualiserOnly(visualiserOnly),
|
||||||
AudioBackgroundThread("VisualiserComponent" + juce::String(parent != nullptr ? " Child" : ""), threadManager),
|
AudioBackgroundThread("VisualiserComponent" + juce::String(parent != nullptr ? " Child" : ""), processor.threadManager),
|
||||||
parent(parent) {
|
parent(parent) {
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
addAndMakeVisible(ffmpegDownloader);
|
addAndMakeVisible(ffmpegDownloader);
|
||||||
|
@ -45,11 +43,18 @@ VisualiserComponent::VisualiserComponent(
|
||||||
ffmpegDownloader.onSuccessfulDownload = [this] {
|
ffmpegDownloader.onSuccessfulDownload = [this] {
|
||||||
juce::MessageManager::callAsync([this] {
|
juce::MessageManager::callAsync([this] {
|
||||||
record.setEnabled(true);
|
record.setEnabled(true);
|
||||||
|
juce::Timer::callAfterDelay(3000, [this] {
|
||||||
|
juce::MessageManager::callAsync([this] {
|
||||||
|
ffmpegDownloader.setVisible(false);
|
||||||
|
downloading = false;
|
||||||
|
resized();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
haltRecording = [this] {
|
audioProcessor.haltRecording = [this] {
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,6 +115,8 @@ VisualiserComponent::VisualiserComponent(
|
||||||
popoutWindow();
|
popoutWindow();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
addAndMakeVisible(audioPlayer);
|
||||||
|
|
||||||
setFullScreen(false);
|
setFullScreen(false);
|
||||||
|
|
||||||
openGLContext.setRenderer(this);
|
openGLContext.setRenderer(this);
|
||||||
|
@ -121,7 +128,7 @@ VisualiserComponent::VisualiserComponent(
|
||||||
VisualiserComponent::~VisualiserComponent() {
|
VisualiserComponent::~VisualiserComponent() {
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
if (parent == nullptr) {
|
if (parent == nullptr) {
|
||||||
haltRecording = nullptr;
|
audioProcessor.haltRecording = nullptr;
|
||||||
}
|
}
|
||||||
openGLContext.detach();
|
openGLContext.detach();
|
||||||
setShouldBeRunning(false, [this] {
|
setShouldBeRunning(false, [this] {
|
||||||
|
@ -255,6 +262,7 @@ void VisualiserComponent::setPaused(bool paused) {
|
||||||
active = !paused;
|
active = !paused;
|
||||||
renderingSemaphore.release();
|
renderingSemaphore.release();
|
||||||
setShouldBeRunning(active);
|
setShouldBeRunning(active);
|
||||||
|
audioPlayer.setPaused(paused);
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,8 +297,8 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
|
|
||||||
if (recording) {
|
if (recording) {
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
recordingVideo = recordingParameters.recordingVideo();
|
recordingVideo = recordingSettings.recordingVideo();
|
||||||
recordingAudio = recordingParameters.recordingAudio();
|
recordingAudio = recordingSettings.recordingAudio();
|
||||||
if (!recordingVideo && !recordingAudio) {
|
if (!recordingVideo && !recordingAudio) {
|
||||||
record.setToggleState(false, juce::NotificationType::dontSendNotification);
|
record.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||||
return;
|
return;
|
||||||
|
@ -311,6 +319,9 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
if (result == 1) {
|
if (result == 1) {
|
||||||
record.setEnabled(false);
|
record.setEnabled(false);
|
||||||
ffmpegDownloader.download();
|
ffmpegDownloader.download();
|
||||||
|
ffmpegDownloader.setVisible(true);
|
||||||
|
downloading = true;
|
||||||
|
resized();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
record.setToggleState(false, juce::NotificationType::dontSendNotification);
|
record.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||||
|
@ -325,10 +336,10 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
" -s " + resolution +
|
" -s " + resolution +
|
||||||
" -i -" +
|
" -i -" +
|
||||||
" -threads 4" +
|
" -threads 4" +
|
||||||
" -preset " + recordingParameters.getCompressionPreset() +
|
" -preset " + recordingSettings.getCompressionPreset() +
|
||||||
" -y" +
|
" -y" +
|
||||||
" -pix_fmt yuv420p" +
|
" -pix_fmt yuv420p" +
|
||||||
" -crf " + juce::String(recordingParameters.getCRF()) +
|
" -crf " + juce::String(recordingSettings.getCRF()) +
|
||||||
" -vf vflip" +
|
" -vf vflip" +
|
||||||
" \"" + tempVideoFile->getFile().getFullPathName() + "\"";
|
" \"" + tempVideoFile->getFile().getFullPathName() + "\"";
|
||||||
|
|
||||||
|
@ -366,7 +377,7 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
audioRecorder.stop();
|
audioRecorder.stop();
|
||||||
juce::String extension = "wav";
|
juce::String extension = "wav";
|
||||||
#endif
|
#endif
|
||||||
chooser = std::make_unique<juce::FileChooser>("Save recording", lastOpenedDirectory, "*." + extension);
|
chooser = std::make_unique<juce::FileChooser>("Save recording", audioProcessor.lastOpenedDirectory, "*." + extension);
|
||||||
auto flags = juce::FileBrowserComponent::saveMode | juce::FileBrowserComponent::canSelectFiles | juce::FileBrowserComponent::warnAboutOverwriting;
|
auto flags = juce::FileBrowserComponent::saveMode | juce::FileBrowserComponent::canSelectFiles | juce::FileBrowserComponent::warnAboutOverwriting;
|
||||||
|
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
|
@ -381,7 +392,7 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
} else if (wasRecordingVideo) {
|
} else if (wasRecordingVideo) {
|
||||||
tempVideoFile->getFile().copyFileTo(file);
|
tempVideoFile->getFile().copyFileTo(file);
|
||||||
}
|
}
|
||||||
lastOpenedDirectory = file.getParentDirectory();
|
audioProcessor.lastOpenedDirectory = file.getParentDirectory();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
|
@ -389,7 +400,7 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
auto file = chooser.getResult();
|
auto file = chooser.getResult();
|
||||||
if (file != juce::File()) {
|
if (file != juce::File()) {
|
||||||
tempAudioFile->getFile().copyFileTo(file);
|
tempAudioFile->getFile().copyFileTo(file);
|
||||||
lastOpenedDirectory = file.getParentDirectory();
|
audioProcessor.lastOpenedDirectory = file.getParentDirectory();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
@ -430,11 +441,13 @@ void VisualiserComponent::resized() {
|
||||||
stopwatch.setVisible(false);
|
stopwatch.setVisible(false);
|
||||||
}
|
}
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
if (child == nullptr) {
|
if (child == nullptr && downloading) {
|
||||||
auto bounds = buttons.removeFromRight(160);
|
auto bounds = buttons.removeFromRight(160);
|
||||||
ffmpegDownloader.setBounds(bounds.withSizeKeepingCentre(bounds.getWidth() - 10, bounds.getHeight() - 10));
|
ffmpegDownloader.setBounds(bounds.withSizeKeepingCentre(bounds.getWidth() - 10, bounds.getHeight() - 10));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
buttons.removeFromRight(10); // padding
|
||||||
|
audioPlayer.setBounds(buttons);
|
||||||
viewportArea = area;
|
viewportArea = area;
|
||||||
viewportChanged(viewportArea);
|
viewportChanged(viewportArea);
|
||||||
}
|
}
|
||||||
|
@ -447,15 +460,13 @@ void VisualiserComponent::popoutWindow() {
|
||||||
#endif
|
#endif
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
auto visualiser = new VisualiserComponent(
|
auto visualiser = new VisualiserComponent(
|
||||||
lastOpenedDirectory,
|
audioProcessor,
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
sharedTextureManager,
|
sharedTextureManager,
|
||||||
#endif
|
#endif
|
||||||
ffmpegFile,
|
ffmpegFile,
|
||||||
haltRecording,
|
|
||||||
threadManager,
|
|
||||||
settings,
|
settings,
|
||||||
recordingParameters,
|
recordingSettings,
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
visualiser->settings.setLookAndFeel(&getLookAndFeel());
|
visualiser->settings.setLookAndFeel(&getLookAndFeel());
|
||||||
|
@ -481,12 +492,12 @@ void VisualiserComponent::childUpdated() {
|
||||||
#endif
|
#endif
|
||||||
record.setVisible(child == nullptr);
|
record.setVisible(child == nullptr);
|
||||||
if (child != nullptr) {
|
if (child != nullptr) {
|
||||||
haltRecording = [this] {
|
audioProcessor.haltRecording = [this] {
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
child->setRecording(false);
|
child->setRecording(false);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
haltRecording = [this] {
|
audioProcessor.haltRecording = [this] {
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -660,7 +671,7 @@ void VisualiserComponent::renderOpenGL() {
|
||||||
|
|
||||||
void VisualiserComponent::viewportChanged(juce::Rectangle<int> area) {
|
void VisualiserComponent::viewportChanged(juce::Rectangle<int> area) {
|
||||||
using namespace juce::gl;
|
using namespace juce::gl;
|
||||||
|
|
||||||
if (openGLContext.isAttached()) {
|
if (openGLContext.isAttached()) {
|
||||||
float realWidth = area.getWidth() * renderScale;
|
float realWidth = area.getWidth() * renderScale;
|
||||||
float realHeight = area.getHeight() * renderScale;
|
float realHeight = area.getHeight() * renderScale;
|
||||||
|
@ -1175,11 +1186,7 @@ void VisualiserComponent::checkGLErrors(const juce::String& location) {
|
||||||
|
|
||||||
|
|
||||||
void VisualiserComponent::paint(juce::Graphics& g) {
|
void VisualiserComponent::paint(juce::Graphics& g) {
|
||||||
#if SOSCI_FEATURES
|
|
||||||
g.setColour(settings.getScreenType() == ScreenType::Real ? Colours::dark : Colours::veryDark);
|
|
||||||
#else
|
|
||||||
g.setColour(Colours::veryDark);
|
g.setColour(Colours::veryDark);
|
||||||
#endif
|
|
||||||
g.fillRect(buttonRow);
|
g.fillRect(buttonRow);
|
||||||
if (!active) {
|
if (!active) {
|
||||||
// draw a translucent overlay
|
// draw a translucent overlay
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "../components/DownloaderComponent.h"
|
#include "../components/DownloaderComponent.h"
|
||||||
#include "../concurrency/WriteProcess.h"
|
#include "../concurrency/WriteProcess.h"
|
||||||
#include "../audio/AudioRecorder.h"
|
#include "../audio/AudioRecorder.h"
|
||||||
|
#include "../wav/WavParser.h"
|
||||||
|
#include "../components/AudioPlayerComponent.h"
|
||||||
|
|
||||||
#define FILE_RENDER_DUMMY 0
|
#define FILE_RENDER_DUMMY 0
|
||||||
#define FILE_RENDER_PNG 1
|
#define FILE_RENDER_PNG 1
|
||||||
|
@ -29,19 +31,18 @@ struct Texture {
|
||||||
int height;
|
int height;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CommonAudioProcessor;
|
||||||
class VisualiserWindow;
|
class VisualiserWindow;
|
||||||
class VisualiserComponent : public juce::Component, public AudioBackgroundThread, public juce::MouseListener, public juce::OpenGLRenderer, public juce::AsyncUpdater {
|
class VisualiserComponent : public juce::Component, public AudioBackgroundThread, public juce::MouseListener, public juce::OpenGLRenderer, public juce::AsyncUpdater {
|
||||||
public:
|
public:
|
||||||
VisualiserComponent(
|
VisualiserComponent(
|
||||||
juce::File& lastOpenedDirectory,
|
CommonAudioProcessor& processor,
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
SharedTextureManager& sharedTextureManager,
|
SharedTextureManager& sharedTextureManager,
|
||||||
#endif
|
#endif
|
||||||
juce::File ffmpegFile,
|
juce::File ffmpegFile,
|
||||||
std::function<void()>& haltRecording,
|
|
||||||
AudioBackgroundThreadManager& threadManager,
|
|
||||||
VisualiserSettings& settings,
|
VisualiserSettings& settings,
|
||||||
RecordingParameters& recordingParameters,
|
RecordingSettings& recordingSettings,
|
||||||
VisualiserComponent* parent = nullptr,
|
VisualiserComponent* parent = nullptr,
|
||||||
bool visualiserOnly = false
|
bool visualiserOnly = false
|
||||||
);
|
);
|
||||||
|
@ -76,13 +77,13 @@ public:
|
||||||
std::atomic<bool> active = true;
|
std::atomic<bool> active = true;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CommonAudioProcessor& audioProcessor;
|
||||||
|
|
||||||
float intensity;
|
float intensity;
|
||||||
const double FRAME_RATE = 60.0;
|
const double FRAME_RATE = 60.0;
|
||||||
|
|
||||||
bool visualiserOnly;
|
bool visualiserOnly;
|
||||||
std::function<void()>& haltRecording;
|
AudioPlayerComponent audioPlayer{audioProcessor};
|
||||||
|
|
||||||
AudioBackgroundThreadManager& threadManager;
|
|
||||||
|
|
||||||
SvgButton fullScreenButton{ "fullScreen", BinaryData::fullscreen_svg, juce::Colours::white, juce::Colours::white };
|
SvgButton fullScreenButton{ "fullScreen", BinaryData::fullscreen_svg, juce::Colours::white, juce::Colours::white };
|
||||||
SvgButton popOutButton{ "popOut", BinaryData::open_in_new_svg, juce::Colours::white, juce::Colours::white };
|
SvgButton popOutButton{ "popOut", BinaryData::open_in_new_svg, juce::Colours::white, juce::Colours::white };
|
||||||
|
@ -97,12 +98,13 @@ private:
|
||||||
std::function<void(FullScreenMode)> fullScreenCallback;
|
std::function<void(FullScreenMode)> fullScreenCallback;
|
||||||
|
|
||||||
VisualiserSettings& settings;
|
VisualiserSettings& settings;
|
||||||
RecordingParameters& recordingParameters;
|
RecordingSettings& recordingSettings;
|
||||||
juce::File ffmpegFile;
|
juce::File ffmpegFile;
|
||||||
bool recordingAudio = true;
|
bool recordingAudio = true;
|
||||||
|
|
||||||
#if SOSCI_FEATURES
|
#if SOSCI_FEATURES
|
||||||
bool recordingVideo = true;
|
bool recordingVideo = true;
|
||||||
|
bool downloading = false;
|
||||||
|
|
||||||
long numFrames = 0;
|
long numFrames = 0;
|
||||||
std::vector<unsigned char> framePixels;
|
std::vector<unsigned char> framePixels;
|
||||||
|
@ -144,7 +146,6 @@ private:
|
||||||
StopwatchComponent stopwatch;
|
StopwatchComponent stopwatch;
|
||||||
SvgButton record{"Record", BinaryData::record_svg, juce::Colours::red, juce::Colours::red.withAlpha(0.01f)};
|
SvgButton record{"Record", BinaryData::record_svg, juce::Colours::red, juce::Colours::red.withAlpha(0.01f)};
|
||||||
|
|
||||||
juce::File& lastOpenedDirectory;
|
|
||||||
std::unique_ptr<juce::FileChooser> chooser;
|
std::unique_ptr<juce::FileChooser> chooser;
|
||||||
std::unique_ptr<juce::TemporaryFile> tempAudioFile;
|
std::unique_ptr<juce::TemporaryFile> tempAudioFile;
|
||||||
AudioRecorder audioRecorder;
|
AudioRecorder audioRecorder;
|
||||||
|
@ -260,7 +261,6 @@ private:
|
||||||
void viewportChanged(juce::Rectangle<int> area);
|
void viewportChanged(juce::Rectangle<int> area);
|
||||||
|
|
||||||
void renderScope(const std::vector<float>& xPoints, const std::vector<float>& yPoints, const std::vector<float>& zPoints);
|
void renderScope(const std::vector<float>& xPoints, const std::vector<float>& yPoints, const std::vector<float>& zPoints);
|
||||||
int renderAudioFile(juce::File& sourceAudio, int method = 1, int width = 1024, int height = 1024);
|
|
||||||
|
|
||||||
double getSweepIncrement();
|
double getSweepIncrement();
|
||||||
|
|
||||||
|
|
|
@ -307,11 +307,12 @@ private:
|
||||||
juce::Component& component;
|
juce::Component& component;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SettingsWindow : public juce::DocumentWindow {
|
class SettingsWindow : public juce::DialogWindow {
|
||||||
public:
|
public:
|
||||||
SettingsWindow(juce::String name, juce::Component& component) : juce::DocumentWindow(name, Colours::darker, juce::DocumentWindow::TitleBarButtons::closeButton), component(component) {
|
SettingsWindow(juce::String name, juce::Component& component) : juce::DialogWindow(name, Colours::darker, true, true), component(component) {
|
||||||
juce::Component::addAndMakeVisible(viewport);
|
setContentComponent(&viewport);
|
||||||
setResizable(false, false);
|
setResizable(false, false);
|
||||||
|
viewport.setColour(juce::ScrollBar::trackColourId, juce::Colours::white);
|
||||||
viewport.setViewedComponent(&component, false);
|
viewport.setViewedComponent(&component, false);
|
||||||
viewport.setScrollBarsShown(true, false, true, false);
|
viewport.setScrollBarsShown(true, false, true, false);
|
||||||
setAlwaysOnTop(true);
|
setAlwaysOnTop(true);
|
||||||
|
@ -321,10 +322,6 @@ public:
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resized() override {
|
|
||||||
viewport.setBounds(getLocalBounds());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
juce::Viewport viewport;
|
juce::Viewport viewport;
|
||||||
juce::Component& component;
|
juce::Component& component;
|
||||||
|
|
|
@ -9,7 +9,8 @@ WavParser::WavParser(CommonAudioProcessor& p, std::unique_ptr<juce::InputStream>
|
||||||
if (reader == nullptr) {
|
if (reader == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto* afSource = new juce::AudioFormatReaderSource(reader, true);
|
afSource = new juce::AudioFormatReaderSource(reader, true);
|
||||||
|
totalSamples = afSource->getTotalLength();
|
||||||
afSource->setLooping(true);
|
afSource->setLooping(true);
|
||||||
source = std::make_unique<juce::ResamplingAudioSource>(afSource, true);
|
source = std::make_unique<juce::ResamplingAudioSource>(afSource, true);
|
||||||
fileSampleRate = reader->sampleRate;
|
fileSampleRate = reader->sampleRate;
|
||||||
|
@ -32,11 +33,23 @@ OsciPoint WavParser::getSample() {
|
||||||
if (currentSampleRate != audioProcessor.currentSampleRate) {
|
if (currentSampleRate != audioProcessor.currentSampleRate) {
|
||||||
setSampleRate(audioProcessor.currentSampleRate);
|
setSampleRate(audioProcessor.currentSampleRate);
|
||||||
}
|
}
|
||||||
if (source == nullptr) {
|
if (source == nullptr || paused) {
|
||||||
return OsciPoint();
|
return OsciPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
source->getNextAudioBlock(juce::AudioSourceChannelInfo(audioBuffer));
|
source->getNextAudioBlock(juce::AudioSourceChannelInfo(audioBuffer));
|
||||||
|
currentSample += source->getResamplingRatio();
|
||||||
|
counter++;
|
||||||
|
if (currentSample >= totalSamples && afSource->isLooping()) {
|
||||||
|
currentSample = 0;
|
||||||
|
counter = 0;
|
||||||
|
afSource->setNextReadPosition(0);
|
||||||
|
}
|
||||||
|
if (counter % currentSampleRate == 0) {
|
||||||
|
if (onProgress != nullptr) {
|
||||||
|
onProgress((double)currentSample / totalSamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (audioBuffer.getNumChannels() == 1) {
|
if (audioBuffer.getNumChannels() == 1) {
|
||||||
return OsciPoint(audioBuffer.getSample(0, 0), audioBuffer.getSample(0, 0));
|
return OsciPoint(audioBuffer.getSample(0, 0), audioBuffer.getSample(0, 0));
|
||||||
|
@ -44,3 +57,29 @@ OsciPoint WavParser::getSample() {
|
||||||
return OsciPoint(audioBuffer.getSample(0, 0), audioBuffer.getSample(1, 0));
|
return OsciPoint(audioBuffer.getSample(0, 0), audioBuffer.getSample(1, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WavParser::setProgress(double progress) {
|
||||||
|
if (source == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
afSource->setNextReadPosition(progress * totalSamples);
|
||||||
|
currentSample = progress * totalSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavParser::setLooping(bool looping) {
|
||||||
|
afSource->setLooping(looping);
|
||||||
|
this->looping = looping;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WavParser::isLooping() {
|
||||||
|
return looping;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavParser::setPaused(bool paused) {
|
||||||
|
this->paused = paused;
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WavParser::isPaused() {
|
||||||
|
return paused;
|
||||||
|
}
|
||||||
|
|
|
@ -10,12 +10,25 @@ public:
|
||||||
|
|
||||||
OsciPoint getSample();
|
OsciPoint getSample();
|
||||||
|
|
||||||
|
void setProgress(double progress);
|
||||||
|
void setPaused(bool paused);
|
||||||
|
bool isPaused();
|
||||||
|
void setLooping(bool looping);
|
||||||
|
bool isLooping();
|
||||||
|
|
||||||
|
std::function<void(double)> onProgress;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setSampleRate(double sampleRate);
|
void setSampleRate(double sampleRate);
|
||||||
|
|
||||||
|
juce::AudioFormatReaderSource* afSource;
|
||||||
|
bool looping = true;
|
||||||
std::unique_ptr<juce::ResamplingAudioSource> source;
|
std::unique_ptr<juce::ResamplingAudioSource> source;
|
||||||
juce::AudioBuffer<float> audioBuffer;
|
juce::AudioBuffer<float> audioBuffer;
|
||||||
int currentSample = 0;
|
long totalSamples;
|
||||||
|
long counter = 0;
|
||||||
|
std::atomic<double> currentSample = 0;
|
||||||
|
std::atomic<bool> paused = false;
|
||||||
int fileSampleRate;
|
int fileSampleRate;
|
||||||
int currentSampleRate;
|
int currentSampleRate;
|
||||||
CommonAudioProcessor& audioProcessor;
|
CommonAudioProcessor& audioProcessor;
|
||||||
|
|
|
@ -58,11 +58,14 @@
|
||||||
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
|
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
|
||||||
<FILE id="f2D5tv" name="pause.svg" compile="0" resource="1" file="Resources/svg/pause.svg"/>
|
<FILE id="f2D5tv" name="pause.svg" compile="0" resource="1" file="Resources/svg/pause.svg"/>
|
||||||
<FILE id="D2AI1b" name="pencil.svg" compile="0" resource="1" file="Resources/svg/pencil.svg"/>
|
<FILE id="D2AI1b" name="pencil.svg" compile="0" resource="1" file="Resources/svg/pencil.svg"/>
|
||||||
|
<FILE id="sfWuFd" name="play.svg" compile="0" resource="1" file="Resources/svg/play.svg"/>
|
||||||
<FILE id="PFc2q2" name="random.svg" compile="0" resource="1" file="Resources/svg/random.svg"/>
|
<FILE id="PFc2q2" name="random.svg" compile="0" resource="1" file="Resources/svg/random.svg"/>
|
||||||
<FILE id="CE6di2" name="range.svg" compile="0" resource="1" file="Resources/svg/range.svg"/>
|
<FILE id="CE6di2" name="range.svg" compile="0" resource="1" file="Resources/svg/range.svg"/>
|
||||||
<FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/>
|
<FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/>
|
||||||
|
<FILE id="vOGcgi" name="repeat.svg" compile="0" resource="1" file="Resources/svg/repeat.svg"/>
|
||||||
<FILE id="OaqZb1" name="right_arrow.svg" compile="0" resource="1" file="Resources/svg/right_arrow.svg"/>
|
<FILE id="OaqZb1" name="right_arrow.svg" compile="0" resource="1" file="Resources/svg/right_arrow.svg"/>
|
||||||
<FILE id="yiDo4s" name="spout.svg" compile="0" resource="1" file="Resources/svg/spout.svg"/>
|
<FILE id="yiDo4s" name="spout.svg" compile="0" resource="1" file="Resources/svg/spout.svg"/>
|
||||||
|
<FILE id="EOWhGi" name="stop.svg" compile="0" resource="1" file="Resources/svg/stop.svg"/>
|
||||||
<FILE id="rXjNlx" name="threshold.svg" compile="0" resource="1" file="Resources/svg/threshold.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="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"/>
|
<FILE id="qC6QiP" name="volume.svg" compile="0" resource="1" file="Resources/svg/volume.svg"/>
|
||||||
|
@ -148,6 +151,10 @@
|
||||||
file="Source/components/AboutComponent.cpp"/>
|
file="Source/components/AboutComponent.cpp"/>
|
||||||
<FILE id="vDlOTn" name="AboutComponent.h" compile="0" resource="0"
|
<FILE id="vDlOTn" name="AboutComponent.h" compile="0" resource="0"
|
||||||
file="Source/components/AboutComponent.h"/>
|
file="Source/components/AboutComponent.h"/>
|
||||||
|
<FILE id="xxiMAy" name="AudioPlayerComponent.cpp" compile="1" resource="0"
|
||||||
|
file="Source/components/AudioPlayerComponent.cpp"/>
|
||||||
|
<FILE id="DSvDMv" name="AudioPlayerComponent.h" compile="0" resource="0"
|
||||||
|
file="Source/components/AudioPlayerComponent.h"/>
|
||||||
<FILE id="kUinTt" name="ComponentList.cpp" compile="1" resource="0"
|
<FILE id="kUinTt" name="ComponentList.cpp" compile="1" resource="0"
|
||||||
file="Source/components/ComponentList.cpp"/>
|
file="Source/components/ComponentList.cpp"/>
|
||||||
<FILE id="HGTPEW" name="ComponentList.h" compile="0" resource="0" file="Source/components/ComponentList.h"/>
|
<FILE id="HGTPEW" name="ComponentList.h" compile="0" resource="0" file="Source/components/ComponentList.h"/>
|
||||||
|
|
|
@ -53,11 +53,14 @@
|
||||||
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
|
<FILE id="pSc1mq" name="osci.svg" compile="0" resource="1" file="Resources/svg/osci.svg"/>
|
||||||
<FILE id="f2D5tv" name="pause.svg" compile="0" resource="1" file="Resources/svg/pause.svg"/>
|
<FILE id="f2D5tv" name="pause.svg" compile="0" resource="1" file="Resources/svg/pause.svg"/>
|
||||||
<FILE id="D2AI1b" name="pencil.svg" compile="0" resource="1" file="Resources/svg/pencil.svg"/>
|
<FILE id="D2AI1b" name="pencil.svg" compile="0" resource="1" file="Resources/svg/pencil.svg"/>
|
||||||
|
<FILE id="Tf7MT4" name="play.svg" compile="0" resource="1" file="Resources/svg/play.svg"/>
|
||||||
<FILE id="PFc2q2" name="random.svg" compile="0" resource="1" file="Resources/svg/random.svg"/>
|
<FILE id="PFc2q2" name="random.svg" compile="0" resource="1" file="Resources/svg/random.svg"/>
|
||||||
<FILE id="CE6di2" name="range.svg" compile="0" resource="1" file="Resources/svg/range.svg"/>
|
<FILE id="CE6di2" name="range.svg" compile="0" resource="1" file="Resources/svg/range.svg"/>
|
||||||
<FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/>
|
<FILE id="n79IAy" name="record.svg" compile="0" resource="1" file="Resources/svg/record.svg"/>
|
||||||
|
<FILE id="WDxwSi" name="repeat.svg" compile="0" resource="1" file="Resources/svg/repeat.svg"/>
|
||||||
<FILE id="OaqZb1" name="right_arrow.svg" compile="0" resource="1" file="Resources/svg/right_arrow.svg"/>
|
<FILE id="OaqZb1" name="right_arrow.svg" compile="0" resource="1" file="Resources/svg/right_arrow.svg"/>
|
||||||
<FILE id="z3A7FT" name="spout.svg" compile="0" resource="1" file="Resources/svg/spout.svg"/>
|
<FILE id="z3A7FT" name="spout.svg" compile="0" resource="1" file="Resources/svg/spout.svg"/>
|
||||||
|
<FILE id="wD6mre" name="stop.svg" compile="0" resource="1" file="Resources/svg/stop.svg"/>
|
||||||
<FILE id="rXjNlx" name="threshold.svg" compile="0" resource="1" file="Resources/svg/threshold.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="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"/>
|
<FILE id="qC6QiP" name="volume.svg" compile="0" resource="1" file="Resources/svg/volume.svg"/>
|
||||||
|
@ -102,6 +105,10 @@
|
||||||
file="Source/components/AboutComponent.cpp"/>
|
file="Source/components/AboutComponent.cpp"/>
|
||||||
<FILE id="FtOv3F" name="AboutComponent.h" compile="0" resource="0"
|
<FILE id="FtOv3F" name="AboutComponent.h" compile="0" resource="0"
|
||||||
file="Source/components/AboutComponent.h"/>
|
file="Source/components/AboutComponent.h"/>
|
||||||
|
<FILE id="bbqJIb" name="AudioPlayerComponent.cpp" compile="1" resource="0"
|
||||||
|
file="Source/components/AudioPlayerComponent.cpp"/>
|
||||||
|
<FILE id="UJoX67" name="AudioPlayerComponent.h" compile="0" resource="0"
|
||||||
|
file="Source/components/AudioPlayerComponent.h"/>
|
||||||
<FILE id="aihIvJ" name="DownloaderComponent.cpp" compile="1" resource="0"
|
<FILE id="aihIvJ" name="DownloaderComponent.cpp" compile="1" resource="0"
|
||||||
file="Source/components/DownloaderComponent.cpp"/>
|
file="Source/components/DownloaderComponent.cpp"/>
|
||||||
<FILE id="wBQEfb" name="DownloaderComponent.h" compile="0" resource="0"
|
<FILE id="wBQEfb" name="DownloaderComponent.h" compile="0" resource="0"
|
||||||
|
@ -198,7 +205,7 @@
|
||||||
</GROUP>
|
</GROUP>
|
||||||
</MAINGROUP>
|
</MAINGROUP>
|
||||||
<JUCEOPTIONS JUCE_STRICT_REFCOUNTEDPOINTER="1" JUCE_VST3_CAN_REPLACE_VST2="0"
|
<JUCEOPTIONS JUCE_STRICT_REFCOUNTEDPOINTER="1" JUCE_VST3_CAN_REPLACE_VST2="0"
|
||||||
JUCE_WIN_PER_MONITOR_DPI_AWARE="0" JUCE_WEB_BROWSER="0"/>
|
JUCE_WIN_PER_MONITOR_DPI_AWARE="0" JUCE_WEB_BROWSER="0" JUCE_USE_MP3AUDIOFORMAT="1"/>
|
||||||
<EXPORTFORMATS>
|
<EXPORTFORMATS>
|
||||||
<LINUX_MAKE targetFolder="Builds/sosci/LinuxMakefile" smallIcon="KigaoN"
|
<LINUX_MAKE targetFolder="Builds/sosci/LinuxMakefile" smallIcon="KigaoN"
|
||||||
bigIcon="KigaoN">
|
bigIcon="KigaoN">
|
||||||
|
|
Ładowanie…
Reference in New Issue