kopia lustrzana https://github.com/jameshball/osci-render
194 wiersze
7.2 KiB
C++
194 wiersze
7.2 KiB
C++
#include "SosciPluginProcessor.h"
|
|
#include "SosciPluginEditor.h"
|
|
#include "audio/EffectParameter.h"
|
|
|
|
SosciAudioProcessor::SosciAudioProcessor() {
|
|
// demo audio file on standalone only
|
|
if (juce::JUCEApplicationBase::isStandaloneApp()) {
|
|
std::unique_ptr<juce::InputStream> stream = std::make_unique<juce::MemoryInputStream>(BinaryData::sosci_flac, BinaryData::sosci_flacSize, false);
|
|
loadAudioFile(std::move(stream));
|
|
}
|
|
|
|
addAllParameters();
|
|
}
|
|
|
|
SosciAudioProcessor::~SosciAudioProcessor() {}
|
|
|
|
void SosciAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) {
|
|
juce::ScopedNoDenormals noDenormals;
|
|
|
|
auto input = getBusBuffer(buffer, true, 0);
|
|
auto output = getBusBuffer(buffer, false, 0);
|
|
float EPSILON = 0.0001f;
|
|
|
|
midiMessages.clear();
|
|
|
|
auto inputArray = input.getArrayOfWritePointers();
|
|
auto outputArray = output.getArrayOfWritePointers();
|
|
|
|
juce::SpinLock::ScopedLockType lock2(wavParserLock);
|
|
bool readingFromWav = wavParser.isInitialised();
|
|
|
|
for (int sample = 0; sample < input.getNumSamples(); ++sample) {
|
|
OsciPoint point;
|
|
|
|
if (readingFromWav) {
|
|
point = wavParser.getSample();
|
|
} else {
|
|
float x = input.getNumChannels() > 0 ? inputArray[0][sample] : 0.0f;
|
|
float y = input.getNumChannels() > 1 ? inputArray[1][sample] : 0.0f;
|
|
float brightness = 1.0f;
|
|
if (input.getNumChannels() > 2 && !forceDisableBrightnessInput) {
|
|
float brightnessChannel = inputArray[2][sample];
|
|
// Only enable brightness if we actually receive a signal on the brightness channel
|
|
if (!brightnessEnabled && brightnessChannel > EPSILON) {
|
|
brightnessEnabled = true;
|
|
}
|
|
if (brightnessEnabled) {
|
|
brightness = brightnessChannel;
|
|
}
|
|
}
|
|
|
|
point = { x, y, brightness };
|
|
}
|
|
|
|
// no negative brightness
|
|
point.z = juce::jlimit(0.0, 1.0, point.z);
|
|
|
|
for (auto& effect : permanentEffects) {
|
|
point = effect->apply(sample, point);
|
|
}
|
|
|
|
// this is the point that the visualiser will draw
|
|
threadManager.write(point, "VisualiserComponent");
|
|
|
|
point.scale(volume, volume, 1.0);
|
|
|
|
// clip
|
|
point.x = juce::jmax(-threshold, juce::jmin(threshold.load(), point.x));
|
|
point.y = juce::jmax(-threshold, juce::jmin(threshold.load(), point.y));
|
|
|
|
// this is the point that the volume component will draw (i.e. post scale/clipping)
|
|
threadManager.write(point, "VolumeComponent");
|
|
|
|
if (output.getNumChannels() > 0) {
|
|
outputArray[0][sample] = point.x;
|
|
}
|
|
if (output.getNumChannels() > 1) {
|
|
outputArray[1][sample] = point.y;
|
|
}
|
|
if (output.getNumChannels() > 2) {
|
|
outputArray[2][sample] = point.z;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SosciAudioProcessor::getStateInformation(juce::MemoryBlock& destData) {
|
|
// we need to stop recording the visualiser when saving the state, otherwise
|
|
// there are issues. This is the only place we can do this because there is
|
|
// no callback when closing the standalone app except for this.
|
|
|
|
if (haltRecording != nullptr && juce::JUCEApplicationBase::isStandaloneApp()) {
|
|
haltRecording();
|
|
}
|
|
|
|
juce::SpinLock::ScopedLockType lock2(effectsLock);
|
|
|
|
std::unique_ptr<juce::XmlElement> xml = std::make_unique<juce::XmlElement>("project");
|
|
xml->setAttribute("version", ProjectInfo::versionString);
|
|
auto effectsXml = xml->createNewChildElement("effects");
|
|
for (auto effect : effects) {
|
|
effect->save(effectsXml->createNewChildElement("effect"));
|
|
}
|
|
|
|
auto booleanParametersXml = xml->createNewChildElement("booleanParameters");
|
|
for (auto parameter : booleanParameters) {
|
|
auto parameterXml = booleanParametersXml->createNewChildElement("parameter");
|
|
parameter->save(parameterXml);
|
|
}
|
|
|
|
auto floatParametersXml = xml->createNewChildElement("floatParameters");
|
|
for (auto parameter : floatParameters) {
|
|
auto parameterXml = floatParametersXml->createNewChildElement("parameter");
|
|
parameter->save(parameterXml);
|
|
}
|
|
|
|
auto intParametersXml = xml->createNewChildElement("intParameters");
|
|
for (auto parameter : intParameters) {
|
|
auto parameterXml = intParametersXml->createNewChildElement("parameter");
|
|
parameter->save(parameterXml);
|
|
}
|
|
|
|
recordingParameters.save(xml.get());
|
|
|
|
copyXmlToBinary(*xml, destData);
|
|
}
|
|
|
|
void SosciAudioProcessor::setStateInformation(const void* data, int sizeInBytes) {
|
|
std::unique_ptr<juce::XmlElement> xml;
|
|
|
|
const uint32_t magicXmlNumber = 0x21324356;
|
|
if (sizeInBytes > 8 && juce::ByteOrder::littleEndianInt(data) == magicXmlNumber) {
|
|
// this is a binary xml format
|
|
xml = getXmlFromBinary(data, sizeInBytes);
|
|
} else {
|
|
// this is a text xml format
|
|
xml = juce::XmlDocument::parse(juce::String((const char*)data, sizeInBytes));
|
|
}
|
|
|
|
if (xml.get() != nullptr && xml->hasTagName("project")) {
|
|
juce::SpinLock::ScopedLockType lock2(effectsLock);
|
|
|
|
auto effectsXml = xml->getChildByName("effects");
|
|
if (effectsXml != nullptr) {
|
|
for (auto effectXml : effectsXml->getChildIterator()) {
|
|
auto effect = getEffect(effectXml->getStringAttribute("id"));
|
|
if (effect != nullptr) {
|
|
effect->load(effectXml);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto booleanParametersXml = xml->getChildByName("booleanParameters");
|
|
if (booleanParametersXml != nullptr) {
|
|
for (auto parameterXml : booleanParametersXml->getChildIterator()) {
|
|
auto parameter = getBooleanParameter(parameterXml->getStringAttribute("id"));
|
|
if (parameter != nullptr) {
|
|
parameter->load(parameterXml);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto floatParametersXml = xml->getChildByName("floatParameters");
|
|
if (floatParametersXml != nullptr) {
|
|
for (auto parameterXml : floatParametersXml->getChildIterator()) {
|
|
auto parameter = getFloatParameter(parameterXml->getStringAttribute("id"));
|
|
if (parameter != nullptr) {
|
|
parameter->load(parameterXml);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto intParametersXml = xml->getChildByName("intParameters");
|
|
if (intParametersXml != nullptr) {
|
|
for (auto parameterXml : intParametersXml->getChildIterator()) {
|
|
auto parameter = getIntParameter(parameterXml->getStringAttribute("id"));
|
|
if (parameter != nullptr) {
|
|
parameter->load(parameterXml);
|
|
}
|
|
}
|
|
}
|
|
|
|
recordingParameters.load(xml.get());
|
|
}
|
|
}
|
|
|
|
juce::AudioProcessorEditor* SosciAudioProcessor::createEditor() {
|
|
auto editor = new SosciPluginEditor(*this);
|
|
return editor;
|
|
}
|
|
|
|
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() {
|
|
return new SosciAudioProcessor();
|
|
}
|