From 557b9f33719dbedd34670b25bd24a9195e81474f Mon Sep 17 00:00:00 2001 From: James H Ball Date: Thu, 22 Aug 2024 16:59:21 +0100 Subject: [PATCH] Add support for .wav and .aiff files --- Source/MainComponent.cpp | 2 +- Source/PluginEditor.cpp | 2 +- Source/parser/FileParser.cpp | 13 +++++++++-- Source/parser/FileParser.h | 3 +++ Source/wav/WavParser.cpp | 43 ++++++++++++++++++++++++++++++++++++ Source/wav/WavParser.h | 22 ++++++++++++++++++ osci-render.jucer | 4 ++++ 7 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 Source/wav/WavParser.cpp create mode 100644 Source/wav/WavParser.h diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index 3f6cad4..f87d182 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -10,7 +10,7 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess fileButton.setButtonText("Choose File(s)"); fileButton.onClick = [this] { - chooser = std::make_unique("Open", audioProcessor.lastOpenedDirectory, "*.obj;*.svg;*.lua;*.txt;*.gpla;*.gif;*.png;*.jpg;*.jpeg"); + chooser = std::make_unique("Open", audioProcessor.lastOpenedDirectory, "*.obj;*.svg;*.lua;*.txt;*.gpla;*.gif;*.png;*.jpg;*.jpeg;*.wav;*.aiff"); auto flags = juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectMultipleItems | juce::FileBrowserComponent::canSelectFiles; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 7f1769b..c1c2406 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -121,7 +121,7 @@ OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() { } bool OscirenderAudioProcessorEditor::isBinaryFile(juce::String name) { - return name.endsWith(".gpla") || name.endsWith(".gif") || name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg"); + return name.endsWith(".gpla") || name.endsWith(".gif") || name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".wav") || name.endsWith(".aiff"); } // parsersLock must be held diff --git a/Source/parser/FileParser.cpp b/Source/parser/FileParser.cpp index 6d8e7e8..568b323 100644 --- a/Source/parser/FileParser.cpp +++ b/Source/parser/FileParser.cpp @@ -18,6 +18,7 @@ void FileParser::parse(juce::String fileId, juce::String extension, std::unique_ gpla = nullptr; lua = nullptr; img = nullptr; + wav = nullptr; if (extension == ".obj") { object = std::make_shared(stream->readEntireStreamAsString().toStdString()); @@ -33,10 +34,12 @@ void FileParser::parse(juce::String fileId, juce::String extension, std::unique_ juce::MemoryBlock buffer{}; int bytesRead = stream->readIntoMemoryBlock(buffer); img = std::make_shared(audioProcessor, extension, buffer); + } else if (extension == ".wav" || extension == ".aiff") { + wav = std::make_shared(audioProcessor, std::move(stream)); } isAnimatable = gpla != nullptr || (img != nullptr && extension == ".gif"); - sampleSource = lua != nullptr || img != nullptr; + sampleSource = lua != nullptr || img != nullptr || wav != nullptr; } std::vector> FileParser::nextFrame() { @@ -72,7 +75,9 @@ Point FileParser::nextSample(lua_State*& L, LuaVariables& vars) { } } else if (img != nullptr) { return img->getSample(); - } + } else if (wav != nullptr) { + return wav->getSample(); + } return Point(); } @@ -122,3 +127,7 @@ std::shared_ptr FileParser::getLua() { std::shared_ptr FileParser::getImg() { return img; } + +std::shared_ptr FileParser::getWav() { + return wav; +} diff --git a/Source/parser/FileParser.h b/Source/parser/FileParser.h index 5750df9..5755fc7 100644 --- a/Source/parser/FileParser.h +++ b/Source/parser/FileParser.h @@ -8,6 +8,7 @@ #include "../gpla/LineArtParser.h" #include "../lua/LuaParser.h" #include "../img/ImageParser.h" +#include "../wav/WavParser.h" class OscirenderAudioProcessor; class FileParser { @@ -29,6 +30,7 @@ public: std::shared_ptr getLineArt(); std::shared_ptr getLua(); std::shared_ptr getImg(); + std::shared_ptr getWav(); bool isAnimatable = false; @@ -46,6 +48,7 @@ private: std::shared_ptr gpla; std::shared_ptr lua; std::shared_ptr img; + std::shared_ptr wav; juce::String fallbackLuaScript = "return { 0.0, 0.0 }"; diff --git a/Source/wav/WavParser.cpp b/Source/wav/WavParser.cpp new file mode 100644 index 0000000..45b1fed --- /dev/null +++ b/Source/wav/WavParser.cpp @@ -0,0 +1,43 @@ +#include "WavParser.h" +#include "../PluginProcessor.h" + + +WavParser::WavParser(OscirenderAudioProcessor& p, std::unique_ptr stream) : audioProcessor(p) { + juce::AudioFormatManager formatManager; + formatManager.registerBasicFormats(); + juce::AudioFormatReader* reader = formatManager.createReaderFor(std::move(stream)); + auto* afSource = new juce::AudioFormatReaderSource(reader, true); + afSource->setLooping(true); + source = std::make_unique(afSource, true); + fileSampleRate = reader->sampleRate; + audioBuffer.setSize(reader->numChannels, 1); + setSampleRate(audioProcessor.currentSampleRate); + source->prepareToPlay(1, audioProcessor.currentSampleRate); +} + +WavParser::~WavParser() { +} + +void WavParser::setSampleRate(double sampleRate) { + double ratio = fileSampleRate / sampleRate; + source->setResamplingRatio(ratio); + source->prepareToPlay(1, sampleRate); + currentSampleRate = sampleRate; +} + +Point WavParser::getSample() { + if (currentSampleRate != audioProcessor.currentSampleRate) { + setSampleRate(audioProcessor.currentSampleRate); + } + if (source == nullptr) { + return Point(); + } + + source->getNextAudioBlock(juce::AudioSourceChannelInfo(audioBuffer)); + + if (audioBuffer.getNumChannels() == 1) { + return Point(audioBuffer.getSample(0, 0), audioBuffer.getSample(0, 0)); + } else { + return Point(audioBuffer.getSample(0, 0), audioBuffer.getSample(1, 0)); + } +} diff --git a/Source/wav/WavParser.h b/Source/wav/WavParser.h new file mode 100644 index 0000000..7504508 --- /dev/null +++ b/Source/wav/WavParser.h @@ -0,0 +1,22 @@ +#pragma once +#include "../shape/Point.h" +#include + +class OscirenderAudioProcessor; +class WavParser { +public: + WavParser(OscirenderAudioProcessor& p, std::unique_ptr stream); + ~WavParser(); + + Point getSample(); + +private: + void setSampleRate(double sampleRate); + + std::unique_ptr source; + juce::AudioBuffer audioBuffer; + int currentSample = 0; + int fileSampleRate; + int currentSampleRate; + OscirenderAudioProcessor& audioProcessor; +}; \ No newline at end of file diff --git a/osci-render.jucer b/osci-render.jucer index 59e19f7..a2eebc5 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -584,6 +584,10 @@ + + + +