kopia lustrzana https://github.com/jameshball/osci-render
Get standalone oscilloscope working with three channel inputs, and migrate BufferConsumer to use Points rather than raw samples
rodzic
44b6dea7ba
commit
08ef65c377
|
@ -222,69 +222,76 @@
|
|||
from woscope by e1ml : https://github.com/m1el/woscope -->
|
||||
|
||||
<script id="gaussianVertex" type="x-shader">
|
||||
#define EPS 1E-6
|
||||
uniform float uInvert;
|
||||
uniform float uSize;
|
||||
uniform float uNEdges;
|
||||
uniform float uFadeAmount;
|
||||
uniform float uIntensity;
|
||||
uniform float uGain;
|
||||
attribute vec2 aStart, aEnd;
|
||||
attribute float aIdx;
|
||||
varying vec4 uvl;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vLen;
|
||||
varying float vSize;
|
||||
void main () {
|
||||
float tang;
|
||||
vec2 current;
|
||||
// All points in quad contain the same data:
|
||||
// segment start point and segment end point.
|
||||
// We determine point position using its index.
|
||||
float idx = mod(aIdx,4.0);
|
||||
#define EPS 1E-6
|
||||
uniform float uInvert;
|
||||
uniform float uSize;
|
||||
uniform float uNEdges;
|
||||
uniform float uFadeAmount;
|
||||
uniform float uIntensity;
|
||||
uniform float uGain;
|
||||
attribute vec3 aStart, aEnd;
|
||||
attribute float aIdx;
|
||||
varying vec4 uvl;
|
||||
varying vec2 vTexCoord;
|
||||
varying float vLen;
|
||||
varying float vSize;
|
||||
void main () {
|
||||
float tang;
|
||||
vec2 current;
|
||||
// All points in quad contain the same data:
|
||||
// segment start point and segment end point.
|
||||
// We determine point position using its index.
|
||||
float idx = mod(aIdx,4.0);
|
||||
|
||||
// `dir` vector is storing the normalized difference
|
||||
// between end and start
|
||||
vec2 dir = (aEnd-aStart)*uGain;
|
||||
uvl.z = length(dir);
|
||||
vec2 aStartPos = aStart.xy;
|
||||
vec2 aEndPos = aEnd.xy;
|
||||
float aStartBrightness = aStart.z;
|
||||
float aEndBrightness = aEnd.z;
|
||||
|
||||
if (uvl.z > EPS)
|
||||
{
|
||||
dir = dir / uvl.z;
|
||||
vSize = 0.006/pow(uvl.z,0.08);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the segment is too short, just draw a square
|
||||
dir = vec2(1.0, 0.0);
|
||||
vSize = 0.006/pow(EPS,0.08);
|
||||
}
|
||||
// `dir` vector is storing the normalized difference
|
||||
// between end and start
|
||||
vec2 dir = (aEndPos-aStartPos)*uGain;
|
||||
uvl.z = length(dir);
|
||||
|
||||
vSize = uSize;
|
||||
vec2 norm = vec2(-dir.y, dir.x);
|
||||
if (uvl.z > EPS)
|
||||
{
|
||||
dir = dir / uvl.z;
|
||||
vSize = 0.006/pow(uvl.z,0.08);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the segment is too short, just draw a square
|
||||
dir = vec2(1.0, 0.0);
|
||||
vSize = 0.006/pow(EPS,0.08);
|
||||
}
|
||||
|
||||
if (idx >= 2.0) {
|
||||
current = aEnd*uGain;
|
||||
tang = 1.0;
|
||||
uvl.x = -vSize;
|
||||
} else {
|
||||
current = aStart*uGain;
|
||||
tang = -1.0;
|
||||
uvl.x = uvl.z + vSize;
|
||||
}
|
||||
// `side` corresponds to shift to the "right" or "left"
|
||||
float side = (mod(idx, 2.0)-0.5)*2.0;
|
||||
uvl.y = side * vSize;
|
||||
vSize = uSize;
|
||||
vec2 norm = vec2(-dir.y, dir.x);
|
||||
|
||||
uvl.w = uIntensity*mix(1.0-uFadeAmount, 1.0, floor(aIdx / 4.0 + 0.5)/uNEdges);
|
||||
if (idx >= 2.0) {
|
||||
current = aEndPos*uGain;
|
||||
tang = 1.0;
|
||||
uvl.x = -vSize;
|
||||
uvl.w = aEndBrightness;
|
||||
} else {
|
||||
current = aStartPos*uGain;
|
||||
tang = -1.0;
|
||||
uvl.x = uvl.z + vSize;
|
||||
uvl.w = aStartBrightness;
|
||||
}
|
||||
// `side` corresponds to shift to the "right" or "left"
|
||||
float side = (mod(idx, 2.0)-0.5)*2.0;
|
||||
uvl.y = side * vSize;
|
||||
|
||||
vec4 pos = vec4((current+(tang*dir+norm*side)*vSize)*uInvert,0.0,1.0);
|
||||
gl_Position = pos;
|
||||
uvl.w *= uIntensity * mix(1.0-uFadeAmount, 1.0, floor(aIdx / 4.0 + 0.5)/uNEdges);
|
||||
|
||||
vec4 pos = vec4((current+(tang*dir+norm*side)*vSize)*uInvert,0.0,1.0);
|
||||
gl_Position = pos;
|
||||
vTexCoord = 0.5*pos.xy+0.5;
|
||||
//float seed = floor(aIdx/4.0);
|
||||
//seed = mod(sin(seed*seed), 7.0);
|
||||
//if (mod(seed/2.0, 1.0)<0.5) gl_Position = vec4(10.0);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="gaussianFragment" type="x-shader">
|
||||
|
|
|
@ -12,8 +12,10 @@ var AudioSystem =
|
|||
this.timePerSample = 1/externalSampleRate;
|
||||
this.oldXSamples = new Float32Array(this.bufferSize);
|
||||
this.oldYSamples = new Float32Array(this.bufferSize);
|
||||
this.oldZSamples = new Float32Array(this.bufferSize);
|
||||
this.smoothedXSamples = new Float32Array(Filter.nSmoothedSamples);
|
||||
this.smoothedYSamples = new Float32Array(Filter.nSmoothedSamples);
|
||||
this.smoothedYSamples = new Float32Array(Filter.nSmoothedSamples);
|
||||
this.smoothedZSamples = new Float32Array(Filter.nSmoothedSamples);
|
||||
},
|
||||
|
||||
startSound : function()
|
||||
|
@ -245,13 +247,13 @@ var Render =
|
|||
|
||||
},
|
||||
|
||||
drawLineTexture : function(xPoints, yPoints)
|
||||
drawLineTexture: function (xPoints, yPoints, zPoints)
|
||||
{
|
||||
this.fadeAmount = Math.min(1, Math.pow(0.5, controls.persistence) * 0.4);
|
||||
this.activateTargetTexture(this.lineTexture);
|
||||
this.fade();
|
||||
//gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
this.drawLine(xPoints, yPoints);
|
||||
this.drawLine(xPoints, yPoints, zPoints);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.targetTexture);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
},
|
||||
|
@ -385,7 +387,7 @@ var Render =
|
|||
}
|
||||
},
|
||||
|
||||
drawLine : function(xPoints, yPoints)
|
||||
drawLine : function(xPoints, yPoints, zPoints)
|
||||
{
|
||||
this.setAdditiveBlending();
|
||||
|
||||
|
@ -394,19 +396,11 @@ var Render =
|
|||
var nPoints = xPoints.length;
|
||||
for (var i=0; i<nPoints; i++)
|
||||
{
|
||||
var p = i*8;
|
||||
scratchVertices[p]=scratchVertices[p+2]=scratchVertices[p+4]=scratchVertices[p+6]=xPoints[i];
|
||||
scratchVertices[p+1]=scratchVertices[p+3]=scratchVertices[p+5]=scratchVertices[p+7]=yPoints[i];
|
||||
/*if (i>0)
|
||||
{
|
||||
var xDelta = xPoints[i]-xPoints[i-1];
|
||||
if (xDelta<0) xDelta = -xDelta;
|
||||
var yDelta = yPoints[i]-yPoints[i-1];
|
||||
if (yDelta<0) yDelta = -yDelta;
|
||||
this.totalLength += xDelta + yDelta;
|
||||
}*/
|
||||
var p = i * 12;
|
||||
scratchVertices[p] = scratchVertices[p + 3] = scratchVertices[p + 6] = scratchVertices[p + 9] = xPoints[i];
|
||||
scratchVertices[p + 1] = scratchVertices[p + 4] = scratchVertices[p + 7] = scratchVertices[p + 10] = yPoints[i];
|
||||
scratchVertices[p + 2] = scratchVertices[p + 5] = scratchVertices[p + 8] = scratchVertices[p + 11] = zPoints[i];
|
||||
}
|
||||
//testOutputElement.value = this.totalLength;
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, scratchVertices, gl.STATIC_DRAW);
|
||||
|
@ -419,8 +413,8 @@ var Render =
|
|||
gl.enableVertexAttribArray(program.aIdx);
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
gl.vertexAttribPointer(program.aStart, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.vertexAttribPointer(program.aEnd, 2, gl.FLOAT, false, 0, 8*4);
|
||||
gl.vertexAttribPointer(program.aStart, 3, gl.FLOAT, false, 0, 0);
|
||||
gl.vertexAttribPointer(program.aEnd, 3, gl.FLOAT, false, 0, 12*4);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadIndexBuffer);
|
||||
gl.vertexAttribPointer(program.aIdx, 1, gl.FLOAT, false, 0, 0);
|
||||
|
||||
|
@ -679,65 +673,79 @@ function doScriptProcessor(bufferBase64) {
|
|||
req.open('GET', "data:application/octet;base64," + bufferBase64);
|
||||
req.responseType = 'arraybuffer';
|
||||
req.onload = function fileLoaded(e) {
|
||||
var dataView = new DataView(e.target.response);
|
||||
|
||||
for (var i = 0; i < xSamples.length; i++) {
|
||||
xSamples[i] = dataView.getFloat32(i * 4 * 2, true);
|
||||
ySamples[i] = dataView.getFloat32(i * 4 * 2 + 4, true);
|
||||
}
|
||||
|
||||
const getSettingsFn = Juce.getNativeFunction("getSettings");
|
||||
getSettingsFn().then(settings => {
|
||||
Juce.getNativeFunction("getSettings")().then(settings => {
|
||||
controls.brightness = settings.brightness;
|
||||
controls.intensity = settings.intensity;
|
||||
controls.intensity = settings.intensity;
|
||||
controls.persistence = settings.persistence;
|
||||
controls.hue = settings.hue;
|
||||
controls.disableFilter = !settings.upsampling;
|
||||
let numChannels = settings.numChannels;
|
||||
|
||||
if (controls.grid !== settings.graticule) {
|
||||
controls.grid = settings.graticule;
|
||||
const image = controls.noise ? 'noise.jpg' : 'empty.jpg';
|
||||
Render.screenTexture = Render.loadTexture(image);
|
||||
}
|
||||
|
||||
if (controls.noise !== settings.smudges) {
|
||||
controls.noise = settings.smudges;
|
||||
const image = controls.noise ? 'noise.jpg' : 'empty.jpg';
|
||||
Render.screenTexture = Render.loadTexture(image);
|
||||
}
|
||||
});
|
||||
|
||||
if (controls.sweepOn) {
|
||||
var gain = Math.pow(2.0, controls.mainGain);
|
||||
var sweepMinTime = controls.sweepMsDiv * 10 / 1000;
|
||||
var triggerValue = controls.sweepTriggerValue;
|
||||
var dataView = new DataView(e.target.response);
|
||||
|
||||
const stride = 4 * numChannels;
|
||||
for (var i = 0; i < xSamples.length; i++) {
|
||||
xSamples[i] = sweepPosition / gain;
|
||||
sweepPosition += 2 * AudioSystem.timePerSample / sweepMinTime;
|
||||
if (sweepPosition > 1.1 && belowTrigger && ySamples[i] >= triggerValue)
|
||||
sweepPosition = -1.3;
|
||||
belowTrigger = ySamples[i] < triggerValue;
|
||||
xSamples[i] = dataView.getFloat32(i * stride, true);
|
||||
ySamples[i] = dataView.getFloat32(i * stride + 4, true);
|
||||
if (numChannels === 3) {
|
||||
zSamples[i] = dataView.getFloat32(i * stride + 8, true);
|
||||
} else {
|
||||
zSamples[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!controls.freezeImage) {
|
||||
if (!controls.disableFilter) {
|
||||
Filter.generateSmoothedSamples(AudioSystem.oldXSamples, xSamples, AudioSystem.smoothedXSamples);
|
||||
Filter.generateSmoothedSamples(AudioSystem.oldYSamples, ySamples, AudioSystem.smoothedYSamples);
|
||||
|
||||
if (!controls.swapXY) Render.drawLineTexture(AudioSystem.smoothedXSamples, AudioSystem.smoothedYSamples);
|
||||
else Render.drawLineTexture(AudioSystem.smoothedYSamples, AudioSystem.smoothedXSamples);
|
||||
if (controls.sweepOn) {
|
||||
var gain = Math.pow(2.0, controls.mainGain);
|
||||
var sweepMinTime = controls.sweepMsDiv * 10 / 1000;
|
||||
var triggerValue = controls.sweepTriggerValue;
|
||||
for (var i = 0; i < xSamples.length; i++) {
|
||||
xSamples[i] = sweepPosition / gain;
|
||||
sweepPosition += 2 * AudioSystem.timePerSample / sweepMinTime;
|
||||
if (sweepPosition > 1.1 && belowTrigger && ySamples[i] >= triggerValue)
|
||||
sweepPosition = -1.3;
|
||||
belowTrigger = ySamples[i] < triggerValue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!controls.swapXY) Render.drawLineTexture(xSamples, ySamples);
|
||||
else Render.drawLineTexture(ySamples, xSamples);
|
||||
|
||||
if (!controls.freezeImage) {
|
||||
if (!controls.disableFilter) {
|
||||
Filter.generateSmoothedSamples(AudioSystem.oldXSamples, xSamples, AudioSystem.smoothedXSamples);
|
||||
Filter.generateSmoothedSamples(AudioSystem.oldYSamples, ySamples, AudioSystem.smoothedYSamples);
|
||||
if (numChannels === 3) {
|
||||
Filter.generateSmoothedSamples(AudioSystem.oldZSamples, zSamples, AudioSystem.smoothedZSamples);
|
||||
} else {
|
||||
AudioSystem.smoothedZSamples.fill(1);
|
||||
}
|
||||
|
||||
if (!controls.swapXY) Render.drawLineTexture(AudioSystem.smoothedXSamples, AudioSystem.smoothedYSamples, AudioSystem.smoothedZSamples);
|
||||
else Render.drawLineTexture(AudioSystem.smoothedYSamples, AudioSystem.smoothedXSamples, AudioSystem.smoothedZSamples);
|
||||
}
|
||||
else {
|
||||
if (!controls.swapXY) Render.drawLineTexture(xSamples, ySamples, zSamples);
|
||||
else Render.drawLineTexture(ySamples, xSamples, zSamples);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < xSamples.length; i++) {
|
||||
AudioSystem.oldXSamples[i] = xSamples[i];
|
||||
AudioSystem.oldYSamples[i] = ySamples[i];
|
||||
}
|
||||
for (var i = 0; i < xSamples.length; i++) {
|
||||
AudioSystem.oldXSamples[i] = xSamples[i];
|
||||
AudioSystem.oldYSamples[i] = ySamples[i];
|
||||
AudioSystem.oldZSamples[i] = zSamples[i];
|
||||
}
|
||||
|
||||
requestAnimationFrame(drawCRTFrame);
|
||||
requestAnimationFrame(drawCRTFrame);
|
||||
});
|
||||
}
|
||||
req.send();
|
||||
}
|
||||
|
@ -748,13 +756,15 @@ function drawCRTFrame(timeStamp) {
|
|||
|
||||
var xSamples = new Float32Array(externalBufferSize);
|
||||
var ySamples = new Float32Array(externalBufferSize);
|
||||
var zSamples = new Float32Array(externalBufferSize);
|
||||
|
||||
Juce.getNativeFunction("bufferSize")().then(bufferSize => {
|
||||
externalBufferSize = bufferSize;
|
||||
Juce.getNativeFunction("sampleRate")().then(sampleRate => {
|
||||
externalSampleRate = sampleRate;
|
||||
xSamples = new Float32Array(externalBufferSize);
|
||||
ySamples = new Float32Array(externalBufferSize);
|
||||
ySamples = new Float32Array(externalBufferSize);
|
||||
zSamples = new Float32Array(externalBufferSize);
|
||||
Render.init();
|
||||
Filter.init(externalBufferSize, 8, 6);
|
||||
AudioSystem.init(externalBufferSize);
|
||||
|
|
|
@ -751,8 +751,7 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, ju
|
|||
{
|
||||
juce::SpinLock::ScopedLockType scope(consumerLock);
|
||||
for (auto consumer : consumers) {
|
||||
consumer->write(x);
|
||||
consumer->write(y);
|
||||
consumer->write(Point(x, y, 1));
|
||||
consumer->notifyIfFull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,17 +12,17 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p)
|
|||
|
||||
setLookAndFeel(&lookAndFeel);
|
||||
|
||||
// #if JUCE_MAC
|
||||
// if (audioProcessor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone) {
|
||||
// usingNativeMenuBar = true;
|
||||
// menuBarModel.setMacMainMenu(&menuBarModel);
|
||||
// }
|
||||
// #endif
|
||||
#if JUCE_MAC
|
||||
if (audioProcessor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone) {
|
||||
usingNativeMenuBar = true;
|
||||
menuBarModel.setMacMainMenu(&menuBarModel);
|
||||
}
|
||||
#endif
|
||||
|
||||
// if (!usingNativeMenuBar) {
|
||||
// menuBar.setModel(&menuBarModel);
|
||||
// addAndMakeVisible(menuBar);
|
||||
// }
|
||||
if (!usingNativeMenuBar) {
|
||||
menuBar.setModel(&menuBarModel);
|
||||
addAndMakeVisible(menuBar);
|
||||
}
|
||||
|
||||
if (juce::JUCEApplicationBase::isStandaloneApp()) {
|
||||
if (juce::TopLevelWindow::getNumTopLevelWindows() > 0) {
|
||||
|
@ -44,6 +44,27 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p)
|
|||
|
||||
addAndMakeVisible(visualiser);
|
||||
|
||||
visualiser.openSettings = [this] {
|
||||
visualiserSettingsWindow.setVisible(true);
|
||||
visualiserSettingsWindow.toFront(true);
|
||||
};
|
||||
|
||||
visualiser.closeSettings = [this] {
|
||||
visualiserSettingsWindow.setVisible(false);
|
||||
};
|
||||
|
||||
visualiserSettingsWindow.setResizable(false, false);
|
||||
#if JUCE_WINDOWS
|
||||
// if not standalone, use native title bar for compatibility with DAWs
|
||||
visualiserSettingsWindow.setUsingNativeTitleBar(processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone);
|
||||
#elif JUCE_MAC
|
||||
visualiserSettingsWindow.setUsingNativeTitleBar(true);
|
||||
#endif
|
||||
visualiserSettings.setLookAndFeel(&getLookAndFeel());
|
||||
visualiserSettings.setSize(550, 280);
|
||||
visualiserSettingsWindow.setContentNonOwned(&visualiserSettings, true);
|
||||
visualiserSettingsWindow.centreWithSize(550, 280);
|
||||
|
||||
setSize(750, 750);
|
||||
setResizable(true, true);
|
||||
setResizeLimits(250, 250, 999999, 999999);
|
||||
|
@ -53,11 +74,11 @@ SosciPluginEditor::~SosciPluginEditor() {
|
|||
setLookAndFeel(nullptr);
|
||||
juce::Desktop::getInstance().setDefaultLookAndFeel(nullptr);
|
||||
|
||||
// #if JUCE_MAC
|
||||
// if (usingNativeMenuBar) {
|
||||
// menuBarModel.setMacMainMenu(nullptr);
|
||||
// }
|
||||
// #endif
|
||||
#if JUCE_MAC
|
||||
if (usingNativeMenuBar) {
|
||||
menuBarModel.setMacMainMenu(nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SosciPluginEditor::paint(juce::Graphics& g) {
|
||||
|
@ -66,11 +87,12 @@ void SosciPluginEditor::paint(juce::Graphics& g) {
|
|||
|
||||
void SosciPluginEditor::resized() {
|
||||
auto area = getLocalBounds();
|
||||
visualiser.setBounds(area);
|
||||
|
||||
// if (!usingNativeMenuBar) {
|
||||
// menuBar.setBounds(area.removeFromTop(25));
|
||||
// }
|
||||
if (!usingNativeMenuBar) {
|
||||
menuBar.setBounds(area.removeFromTop(25));
|
||||
}
|
||||
|
||||
visualiser.setBounds(area);
|
||||
}
|
||||
|
||||
bool SosciPluginEditor::keyPressed(const juce::KeyPress& key) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "components/VisualiserComponent.h"
|
||||
#include "LookAndFeel.h"
|
||||
#include "components/VisualiserSettings.h"
|
||||
#include "components/SosciMainMenuBarModel.h"
|
||||
|
||||
class SosciPluginEditor : public juce::AudioProcessorEditor {
|
||||
public:
|
||||
|
@ -26,17 +27,17 @@ private:
|
|||
public:
|
||||
OscirenderLookAndFeel lookAndFeel;
|
||||
|
||||
VisualiserSettings visualiserSettings = VisualiserSettings(audioProcessor.parameters);
|
||||
VisualiserSettings visualiserSettings = VisualiserSettings(audioProcessor.parameters, 3);
|
||||
SettingsWindow visualiserSettingsWindow = SettingsWindow("Visualiser Settings");
|
||||
VisualiserComponent visualiser{audioProcessor, audioProcessor, visualiserSettings, nullptr, audioProcessor.parameters.legacyVisualiserEnabled->getBoolValue()};
|
||||
|
||||
std::unique_ptr<juce::FileChooser> chooser;
|
||||
// MainMenuBarModel menuBarModel{audioProcessor, *this};
|
||||
// juce::MenuBarComponent menuBar;
|
||||
SosciMainMenuBarModel menuBarModel{*this};
|
||||
juce::MenuBarComponent menuBar;
|
||||
|
||||
juce::TooltipWindow tooltipWindow{nullptr, 0};
|
||||
|
||||
//bool usingNativeMenuBar = false;
|
||||
bool usingNativeMenuBar = false;
|
||||
|
||||
#if JUCE_LINUX
|
||||
juce::OpenGLContext openGlContext;
|
||||
|
|
|
@ -13,14 +13,9 @@
|
|||
//==============================================================================
|
||||
SosciAudioProcessor::SosciAudioProcessor()
|
||||
#ifndef JucePlugin_PreferredChannelConfigurations
|
||||
: AudioProcessor (BusesProperties()
|
||||
#if ! JucePlugin_IsMidiEffect
|
||||
#if ! JucePlugin_IsSynth
|
||||
.withInput ("Input", juce::AudioChannelSet::stereo(), true)
|
||||
#endif
|
||||
.withOutput ("Output", juce::AudioChannelSet::stereo(), true)
|
||||
#endif
|
||||
)
|
||||
: AudioProcessor (BusesProperties().withInput("Input", juce::AudioChannelSet::stereo(), true)
|
||||
.withInput("Brightness", juce::AudioChannelSet::mono(), true)
|
||||
.withOutput("Output", juce::AudioChannelSet::stereo(), true))
|
||||
#endif
|
||||
{
|
||||
// locking isn't necessary here because we are in the constructor
|
||||
|
@ -123,31 +118,12 @@ void SosciAudioProcessor::releaseResources() {
|
|||
// spare memory, etc.
|
||||
}
|
||||
|
||||
#ifndef JucePlugin_PreferredChannelConfigurations
|
||||
bool SosciAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
|
||||
{
|
||||
#if JucePlugin_IsMidiEffect
|
||||
juce::ignoreUnused (layouts);
|
||||
return true;
|
||||
#else
|
||||
// This is the place where you check if the layout is supported.
|
||||
// In this template code we only support mono or stereo.
|
||||
// Some plugin hosts, such as certain GarageBand versions, will only
|
||||
// load plugins that support stereo bus layouts.
|
||||
if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono()
|
||||
&& layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
|
||||
return false;
|
||||
bool SosciAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const {
|
||||
auto numIns = layouts.getMainInputChannels();
|
||||
auto numOuts = layouts.getMainOutputChannels();
|
||||
|
||||
// This checks if the input layout matches the output layout
|
||||
#if ! JucePlugin_IsSynth
|
||||
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
#endif
|
||||
return numIns >= 2 && numOuts >= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
// effectsLock should be held when calling this
|
||||
std::shared_ptr<Effect> SosciAudioProcessor::getEffect(juce::String id) {
|
||||
|
@ -191,25 +167,30 @@ IntParameter* SosciAudioProcessor::getIntParameter(juce::String id) {
|
|||
|
||||
void SosciAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) {
|
||||
juce::ScopedNoDenormals noDenormals;
|
||||
// Audio info variables
|
||||
int numInputs = getTotalNumInputChannels();
|
||||
int numOutputs = getTotalNumOutputChannels();
|
||||
double sampleRate = getSampleRate();
|
||||
|
||||
auto input = getBusBuffer(buffer, true, 0);
|
||||
auto brightness = getBusBuffer(buffer, true, 1);
|
||||
|
||||
midiMessages.clear();
|
||||
|
||||
auto* channelData = buffer.getArrayOfWritePointers();
|
||||
auto inputArray = input.getArrayOfWritePointers();
|
||||
auto brightnessArray = brightness.getArrayOfWritePointers();
|
||||
|
||||
for (int sample = 0; sample < buffer.getNumSamples(); ++sample) {
|
||||
for (int sample = 0; sample < input.getNumSamples(); ++sample) {
|
||||
juce::SpinLock::ScopedLockType scope(consumerLock);
|
||||
|
||||
double x = numOutputs > 0 ? channelData[0][sample] : 0;
|
||||
double y = numOutputs > 1 ? channelData[1][sample] : 0;
|
||||
double z = numOutputs > 2 ? channelData[2][sample] : 0;
|
||||
float x = input.getNumChannels() > 0 ? inputArray[0][sample] : 0.0f;
|
||||
float y = input.getNumChannels() > 1 ? inputArray[1][sample] : 0.0f;
|
||||
float z = brightness.getNumChannels() > 0 ? brightnessArray[0][sample] : 1.0f;
|
||||
|
||||
Point point = { x, y, z };
|
||||
|
||||
for (auto& effect : allEffects) {
|
||||
point = effect->apply(sample, point);
|
||||
}
|
||||
|
||||
for (auto consumer : consumers) {
|
||||
consumer->write(x);
|
||||
consumer->write(y);
|
||||
consumer->write(point);
|
||||
consumer->notifyIfFull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,11 +59,6 @@ public:
|
|||
juce::SpinLock effectsLock;
|
||||
VisualiserParameters parameters;
|
||||
|
||||
private:
|
||||
juce::SpinLock consumerLock;
|
||||
std::vector<std::shared_ptr<BufferConsumer>> consumers;
|
||||
public:
|
||||
|
||||
// shouldn't be accessed by audio thread, but needs to persist when GUI is closed
|
||||
// so should only be accessed by message thread
|
||||
juce::String currentProjectFile;
|
||||
|
|
|
@ -23,7 +23,7 @@ void PitchDetector::run() {
|
|||
|
||||
// buffer is for 2 channels, so we need to only use one
|
||||
for (int i = 0; i < fftSize; i++) {
|
||||
fftData[i] = buffer[2 * i];
|
||||
fftData[i] = buffer[i].x;
|
||||
}
|
||||
|
||||
forwardFFT.performFrequencyOnlyForwardTransform(fftData.data());
|
||||
|
|
|
@ -22,7 +22,7 @@ private:
|
|||
|
||||
juce::CriticalSection consumerLock;
|
||||
std::shared_ptr<BufferConsumer> consumer;
|
||||
std::vector<float> buffer = std::vector<float>(2 * fftSize);
|
||||
std::vector<Point> buffer = std::vector<Point>(fftSize);
|
||||
juce::dsp::FFT forwardFFT{fftOrder};
|
||||
std::array<float, fftSize * 2> fftData;
|
||||
OscirenderAudioProcessor& audioProcessor;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "AboutComponent.h"
|
||||
|
||||
AboutComponent::AboutComponent() {
|
||||
AboutComponent::AboutComponent(const void *image, size_t imageSize, juce::String sectionText) {
|
||||
addAndMakeVisible(logoComponent);
|
||||
addAndMakeVisible(text);
|
||||
|
||||
logo = juce::ImageFileFormat::loadFrom(image, imageSize);
|
||||
|
||||
logoComponent.setImage(logo);
|
||||
|
||||
|
@ -13,15 +15,7 @@ AboutComponent::AboutComponent() {
|
|||
text.setColour(juce::TextEditor::backgroundColourId, juce::Colours::transparentBlack);
|
||||
text.setColour(juce::TextEditor::outlineColourId, juce::Colours::transparentBlack);
|
||||
text.setJustification(juce::Justification(juce::Justification::centred));
|
||||
text.setText(
|
||||
juce::String(ProjectInfo::projectName) + " by " + ProjectInfo::companyName + "\n"
|
||||
"Version " + ProjectInfo::versionString + "\n\n"
|
||||
"A huge thank you to:\n"
|
||||
"DJ_Level_3, for contributing several features to osci-render\n"
|
||||
"BUS ERROR Collective, for providing the source code for the Hilligoss encoder\n"
|
||||
"All the community, for suggesting features and reporting issues!\n\n"
|
||||
"I am open for commissions! Email me at james@ball.sh."
|
||||
);
|
||||
text.setText(sectionText);
|
||||
}
|
||||
|
||||
void AboutComponent::resized() {
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
class AboutComponent : public juce::Component {
|
||||
public:
|
||||
AboutComponent();
|
||||
AboutComponent(const void *image, size_t imageSize, juce::String sectionText);
|
||||
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
juce::Image logo = juce::ImageFileFormat::loadFrom(BinaryData::logo_png, BinaryData::logo_pngSize);
|
||||
juce::Image logo;
|
||||
juce::ImageComponent logoComponent;
|
||||
|
||||
juce::TextEditor text;
|
||||
|
|
|
@ -72,7 +72,15 @@ void MainMenuBarModel::menuItemSelected(int menuItemID, int topLevelMenuIndex) {
|
|||
} break;
|
||||
case 2: {
|
||||
juce::DialogWindow::LaunchOptions options;
|
||||
AboutComponent* about = new AboutComponent();
|
||||
AboutComponent* about = new AboutComponent(BinaryData::logo_png, BinaryData::logo_pngSize,
|
||||
juce::String(ProjectInfo::projectName) + " by " + ProjectInfo::companyName + "\n"
|
||||
"Version " + ProjectInfo::versionString + "\n\n"
|
||||
"A huge thank you to:\n"
|
||||
"DJ_Level_3, for contributing several features to osci-render\n"
|
||||
"BUS ERROR Collective, for providing the source code for the Hilligoss encoder\n"
|
||||
"All the community, for suggesting features and reporting issues!\n\n"
|
||||
"I am open for commissions! Email me at james@ball.sh."
|
||||
);
|
||||
options.content.setOwned(about);
|
||||
options.content->setSize(500, 270);
|
||||
options.dialogTitle = "About";
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
#include "SosciMainMenuBarModel.h"
|
||||
#include "../SosciPluginEditor.h"
|
||||
|
||||
SosciMainMenuBarModel::SosciMainMenuBarModel(SosciPluginEditor& editor) : editor(editor) {}
|
||||
|
||||
SosciMainMenuBarModel::~SosciMainMenuBarModel() {}
|
||||
|
||||
juce::StringArray SosciMainMenuBarModel::getMenuBarNames() {
|
||||
if (editor.processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone) {
|
||||
return juce::StringArray("File", "About", "Audio");
|
||||
} else {
|
||||
return juce::StringArray("File", "About");
|
||||
}
|
||||
}
|
||||
|
||||
juce::PopupMenu SosciMainMenuBarModel::getMenuForIndex(int topLevelMenuIndex, const juce::String& menuName) {
|
||||
juce::PopupMenu menu;
|
||||
|
||||
if (topLevelMenuIndex == 0) {
|
||||
menu.addItem(1, "Open");
|
||||
menu.addItem(2, "Save");
|
||||
menu.addItem(3, "Save As");
|
||||
if (editor.processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone) {
|
||||
menu.addItem(4, "Create New Project");
|
||||
}
|
||||
} else if (topLevelMenuIndex == 1) {
|
||||
menu.addItem(1, "About sosci");
|
||||
} else if (topLevelMenuIndex == 2) {
|
||||
menu.addItem(1, "Settings");
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void SosciMainMenuBarModel::menuItemSelected(int menuItemID, int topLevelMenuIndex) {
|
||||
switch (topLevelMenuIndex) {
|
||||
case 0:
|
||||
switch (menuItemID) {
|
||||
case 1:
|
||||
editor.openProject();
|
||||
break;
|
||||
case 2:
|
||||
editor.saveProject();
|
||||
break;
|
||||
case 3:
|
||||
editor.saveProjectAs();
|
||||
break;
|
||||
case 4:
|
||||
editor.resetToDefault();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1: {
|
||||
juce::DialogWindow::LaunchOptions options;
|
||||
AboutComponent* about = new AboutComponent(BinaryData::logo_png, BinaryData::logo_pngSize, "Sosci");
|
||||
options.content.setOwned(about);
|
||||
options.content->setSize(500, 270);
|
||||
options.dialogTitle = "About";
|
||||
options.dialogBackgroundColour = Colours::dark;
|
||||
options.escapeKeyTriggersCloseButton = true;
|
||||
#if JUCE_WINDOWS
|
||||
// if not standalone, use native title bar for compatibility with DAWs
|
||||
options.useNativeTitleBar = editor.processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone;
|
||||
#elif JUCE_MAC
|
||||
options.useNativeTitleBar = true;
|
||||
#endif
|
||||
options.resizable = false;
|
||||
|
||||
juce::DialogWindow* dw = options.launchAsync();
|
||||
} break;
|
||||
case 2:
|
||||
editor.openAudioSettings();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SosciMainMenuBarModel::menuBarActivated(bool isActive) {}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
#include "AboutComponent.h"
|
||||
|
||||
|
||||
class SosciPluginEditor;
|
||||
class SosciMainMenuBarModel : public juce::MenuBarModel {
|
||||
public:
|
||||
SosciMainMenuBarModel(SosciPluginEditor& editor);
|
||||
~SosciMainMenuBarModel();
|
||||
|
||||
juce::StringArray getMenuBarNames() override;
|
||||
juce::PopupMenu getMenuForIndex(int topLevelMenuIndex, const juce::String& menuName) override;
|
||||
void menuItemSelected(int menuItemID, int topLevelMenuIndex) override;
|
||||
void menuBarActivated(bool isActive);
|
||||
|
||||
private:
|
||||
SosciPluginEditor& editor;
|
||||
};
|
|
@ -73,13 +73,12 @@ void VisualiserComponent::mouseDoubleClick(const juce::MouseEvent& event) {
|
|||
enableFullScreen();
|
||||
}
|
||||
|
||||
void VisualiserComponent::setBuffer(std::vector<float>& newBuffer) {
|
||||
void VisualiserComponent::setBuffer(std::vector<Point>& newBuffer) {
|
||||
juce::CriticalSection::ScopedLockType scope(lock);
|
||||
buffer.clear();
|
||||
int stride = oldVisualiser ? roughness.textBox.getValue() : 1;
|
||||
for (int i = 0; i < newBuffer.size(); i += stride * 2) {
|
||||
for (int i = 0; i < newBuffer.size(); i += stride) {
|
||||
buffer.push_back(newBuffer[i]);
|
||||
buffer.push_back(newBuffer[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,8 +243,8 @@ void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area
|
|||
auto transform = juce::AffineTransform::fromTargetPoints(-1.0f, -1.0f, area.getX(), area.getBottom(), 1.0f, 1.0f, area.getRight(), area.getY(), 1.0f, -1.0f, area.getRight(), area.getBottom());
|
||||
std::vector<juce::Line<float>> lines;
|
||||
|
||||
for (int i = 2; i < buffer.size(); i += 2) {
|
||||
lines.emplace_back(buffer[i - 2], buffer[i - 1], buffer[i], buffer[i + 1]);
|
||||
for (int i = 2; i < buffer.size(); i++) {
|
||||
lines.emplace_back(buffer[i - 1].x, buffer[i - 1].y, buffer[i].x, buffer[i].y);
|
||||
}
|
||||
|
||||
double strength = 15;
|
||||
|
@ -316,7 +315,7 @@ void VisualiserComponent::initialiseBrowser() {
|
|||
complete(settings.getSettings());
|
||||
})
|
||||
.withNativeFunction("bufferSize", [this](auto& var, auto complete) {
|
||||
complete((int) tempBuffer.size() / 2);
|
||||
complete((int) tempBuffer.size());
|
||||
})
|
||||
.withNativeFunction("sampleRate", [this](auto& var, auto complete) {
|
||||
complete(sampleRate);
|
||||
|
@ -330,7 +329,7 @@ void VisualiserComponent::initialiseBrowser() {
|
|||
|
||||
void VisualiserComponent::resetBuffer() {
|
||||
sampleRate = (int) sampleRateManager.getSampleRate();
|
||||
tempBuffer = std::vector<float>(2 * sampleRate * BUFFER_LENGTH_SECS);
|
||||
tempBuffer = std::vector<Point>(sampleRate * BUFFER_LENGTH_SECS);
|
||||
if (!oldVisualiser && isShowing()) {
|
||||
restartBrowser = true;
|
||||
triggerAsyncUpdate();
|
||||
|
@ -344,7 +343,22 @@ void VisualiserComponent::handleAsyncUpdate() {
|
|||
}
|
||||
if (audioUpdated && browser != nullptr) {
|
||||
juce::CriticalSection::ScopedLockType scope(lock);
|
||||
browser->emitEventIfBrowserIsVisible("audioUpdated", juce::Base64::toBase64(buffer.data(), buffer.size() * sizeof(float)));
|
||||
std::vector<float> rawBuffer;
|
||||
if (settings.numChannels == 2) {
|
||||
rawBuffer.reserve(buffer.size() * 2);
|
||||
for (auto& point : buffer) {
|
||||
rawBuffer.push_back(point.x);
|
||||
rawBuffer.push_back(point.y);
|
||||
}
|
||||
} else if (settings.numChannels == 3) {
|
||||
rawBuffer.reserve(buffer.size() * 3);
|
||||
for (auto& point : buffer) {
|
||||
rawBuffer.push_back(point.x);
|
||||
rawBuffer.push_back(point.y);
|
||||
rawBuffer.push_back(point.z);
|
||||
}
|
||||
}
|
||||
browser->emitEventIfBrowserIsVisible("audioUpdated", juce::Base64::toBase64(rawBuffer.data(), rawBuffer.size() * sizeof(float)));
|
||||
audioUpdated = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
void enableFullScreen();
|
||||
void setFullScreenCallback(std::function<void(FullScreenMode)> callback);
|
||||
void mouseDoubleClick(const juce::MouseEvent& event) override;
|
||||
void setBuffer(std::vector<float>& buffer);
|
||||
void setBuffer(std::vector<Point>& buffer);
|
||||
void setColours(juce::Colour backgroundColour, juce::Colour waveformColour);
|
||||
void paintXY(juce::Graphics&, juce::Rectangle<float> bounds);
|
||||
void paint(juce::Graphics&) override;
|
||||
|
@ -62,7 +62,7 @@ private:
|
|||
std::atomic<bool> oldVisualiser;
|
||||
|
||||
juce::CriticalSection lock;
|
||||
std::vector<float> buffer;
|
||||
std::vector<Point> buffer;
|
||||
std::vector<juce::Line<float>> prevLines;
|
||||
juce::Colour backgroundColour, waveformColour;
|
||||
SampleRateManager& sampleRateManager;
|
||||
|
@ -75,7 +75,7 @@ private:
|
|||
SvgButton popOutButton{ "popOut", BinaryData::open_in_new_svg, juce::Colours::white, juce::Colours::white };
|
||||
SvgButton settingsButton{ "settings", BinaryData::cog_svg, juce::Colours::white, juce::Colours::white };
|
||||
|
||||
std::vector<float> tempBuffer;
|
||||
std::vector<Point> tempBuffer;
|
||||
int precision = 4;
|
||||
|
||||
juce::CriticalSection consumerLock;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "../PluginEditor.h"
|
||||
|
||||
|
||||
VisualiserSettings::VisualiserSettings(VisualiserParameters& parameters) : parameters(parameters) {
|
||||
VisualiserSettings::VisualiserSettings(VisualiserParameters& parameters, int numChannels) : parameters(parameters), numChannels(numChannels) {
|
||||
addAndMakeVisible(brightness);
|
||||
addAndMakeVisible(intensity);
|
||||
addAndMakeVisible(persistence);
|
||||
|
@ -41,5 +41,6 @@ juce::var VisualiserSettings::getSettings() {
|
|||
settings->setProperty("graticule", parameters.graticuleEnabled->getBoolValue());
|
||||
settings->setProperty("smudges", parameters.smudgesEnabled->getBoolValue());
|
||||
settings->setProperty("upsampling", parameters.upsamplingEnabled->getBoolValue());
|
||||
settings->setProperty("numChannels", numChannels);
|
||||
return juce::var(settings);
|
||||
}
|
||||
|
|
|
@ -55,13 +55,14 @@ public:
|
|||
|
||||
class VisualiserSettings : public juce::Component {
|
||||
public:
|
||||
VisualiserSettings(VisualiserParameters&);
|
||||
VisualiserSettings(VisualiserParameters&, int numChannels = 2);
|
||||
~VisualiserSettings();
|
||||
|
||||
void resized() override;
|
||||
juce::var getSettings();
|
||||
|
||||
VisualiserParameters& parameters;
|
||||
int numChannels;
|
||||
|
||||
private:
|
||||
EffectComponent brightness{*parameters.brightnessEffect};
|
||||
|
|
|
@ -115,13 +115,13 @@ void VolumeComponent::run() {
|
|||
float leftVolume = 0;
|
||||
float rightVolume = 0;
|
||||
|
||||
for (int i = 0; i < buffer.size(); i += 2) {
|
||||
leftVolume += buffer[i] * buffer[i];
|
||||
rightVolume += buffer[i + 1] * buffer[i + 1];
|
||||
for (int i = 0; i < buffer.size(); i++) {
|
||||
leftVolume += buffer[i].x * buffer[i].x;
|
||||
rightVolume += buffer[i].y * buffer[i].y;
|
||||
}
|
||||
// RMS
|
||||
leftVolume = std::sqrt(leftVolume / (buffer.size() / 2));
|
||||
rightVolume = std::sqrt(rightVolume / (buffer.size() / 2));
|
||||
leftVolume = std::sqrt(leftVolume / buffer.size());
|
||||
rightVolume = std::sqrt(rightVolume / buffer.size());
|
||||
|
||||
if (std::isnan(leftVolume) || std::isnan(rightVolume)) {
|
||||
leftVolume = 0;
|
||||
|
@ -149,5 +149,5 @@ void VolumeComponent::resized() {
|
|||
|
||||
void VolumeComponent::resetBuffer() {
|
||||
sampleRate = (int) audioProcessor.currentSampleRate;
|
||||
buffer = std::vector<float>(2 * BUFFER_DURATION_SECS * sampleRate);
|
||||
buffer = std::vector<Point>(BUFFER_DURATION_SECS * sampleRate);
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ private:
|
|||
const double BUFFER_DURATION_SECS = 0.02;
|
||||
|
||||
int sampleRate = DEFAULT_SAMPLE_RATE;
|
||||
std::vector<float> buffer = std::vector<float>(BUFFER_DURATION_SECS * DEFAULT_SAMPLE_RATE);
|
||||
std::vector<Point> buffer = std::vector<Point>(BUFFER_DURATION_SECS * DEFAULT_SAMPLE_RATE);
|
||||
|
||||
std::atomic<float> leftVolume = 0;
|
||||
std::atomic<float> rightVolume = 0;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "../shape/Point.h"
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
|
@ -41,7 +42,7 @@ public:
|
|||
|
||||
class BufferConsumer {
|
||||
public:
|
||||
BufferConsumer(std::vector<float>& buffer) : buffer(buffer) {}
|
||||
BufferConsumer(std::vector<Point>& buffer) : buffer(buffer) {}
|
||||
|
||||
~BufferConsumer() {}
|
||||
|
||||
|
@ -61,14 +62,14 @@ public:
|
|||
sema.release();
|
||||
}
|
||||
|
||||
void write(double d) {
|
||||
void write(Point point) {
|
||||
if (offset < buffer.size()) {
|
||||
buffer[offset++] = d;
|
||||
buffer[offset++] = point;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<float>& buffer;
|
||||
std::vector<Point>& buffer;
|
||||
Semaphore sema{0};
|
||||
int offset = 0;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "../shape/Point.h"
|
||||
#include "BufferConsumer.h"
|
||||
|
||||
|
||||
|
@ -9,7 +10,7 @@ public:
|
|||
ConsumerManager() {}
|
||||
~ConsumerManager() {}
|
||||
|
||||
std::shared_ptr<BufferConsumer> consumerRegister(std::vector<float>& buffer) {
|
||||
std::shared_ptr<BufferConsumer> consumerRegister(std::vector<Point>& buffer) {
|
||||
std::shared_ptr<BufferConsumer> consumer = std::make_shared<BufferConsumer>(buffer);
|
||||
juce::SpinLock::ScopedLockType scope(consumerLock);
|
||||
consumers.push_back(consumer);
|
||||
|
|
10
sosci.jucer
10
sosci.jucer
|
@ -5,7 +5,7 @@
|
|||
aaxIdentifier="sh.ball.sosci" cppLanguageStandard="20" projectLineFeed=" "
|
||||
headerPath="./include" version="1.0.0" companyName="James H Ball"
|
||||
companyWebsite="https://osci-render.com" companyEmail="james@ball.sh"
|
||||
defines="NOMINMAX=1" pluginAUMainType="'aumf'" binaryDataNamespace="SosciBinaryData">
|
||||
defines="NOMINMAX=1" pluginAUMainType="'aumf'">
|
||||
<MAINGROUP id="j5Ge2T" name="sosci">
|
||||
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
|
||||
<GROUP id="{525C568C-29E9-D0A2-9773-8A04981C5575}" name="images">
|
||||
|
@ -62,10 +62,18 @@
|
|||
file="Source/audio/SampleRateManager.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{CD81913A-7F0E-5898-DA77-5EBEB369DEB1}" name="components">
|
||||
<FILE id="URb7Ok" name="AboutComponent.cpp" compile="1" resource="0"
|
||||
file="Source/components/AboutComponent.cpp"/>
|
||||
<FILE id="FtOv3F" name="AboutComponent.h" compile="0" resource="0"
|
||||
file="Source/components/AboutComponent.h"/>
|
||||
<FILE id="xLAEHK" name="EffectComponent.cpp" compile="1" resource="0"
|
||||
file="Source/components/EffectComponent.cpp"/>
|
||||
<FILE id="u4UCwb" name="EffectComponent.h" compile="0" resource="0"
|
||||
file="Source/components/EffectComponent.h"/>
|
||||
<FILE id="eaHM09" name="SosciMainMenuBarModel.cpp" compile="1" resource="0"
|
||||
file="Source/components/SosciMainMenuBarModel.cpp"/>
|
||||
<FILE id="EymEr3" name="SosciMainMenuBarModel.h" compile="0" resource="0"
|
||||
file="Source/components/SosciMainMenuBarModel.h"/>
|
||||
<FILE id="qzfstC" name="SwitchButton.h" compile="0" resource="0" file="Source/components/SwitchButton.h"/>
|
||||
<FILE id="y3UiR0" name="VisualiserComponent.cpp" compile="1" resource="0"
|
||||
file="Source/components/VisualiserComponent.cpp"/>
|
||||
|
|
Ładowanie…
Reference in New Issue