Compare commits

...

19 Commits

Author SHA1 Message Date
cb069089c0 some ui for #13 2025-12-05 18:37:20 -05:00
234e0d3e8a closes #14 2025-12-05 16:56:59 -05:00
005b924917 closes #12 2025-12-05 16:05:27 -05:00
31e5b1370a closes #11
weak pull to real pitch markers, don't care otherwise
2025-12-04 18:02:24 -05:00
34f565a96c closes #5 - rounding vs truncation error 2025-12-03 18:25:13 -05:00
f637509dbc sends update on load, fixes paramters not showing up 2025-11-11 19:35:31 -05:00
202a73141b closes #10 2025-11-11 19:28:13 -05:00
65f74cd725 primary color and shadows 2025-11-11 18:33:30 -05:00
b3429f03cb closes #8
some ui work
2025-11-11 17:28:45 -05:00
3c6616d1ec closes #6
closes #9
pitch detection runs on known schedule
fixed erratic pitch detection on launch
2025-11-09 11:16:59 -05:00
e89620df27 closes #3
Added freeze pitch and volume controls
2025-11-05 19:17:34 -05:00
f4a0b995ba basic freeze 2025-11-05 18:55:38 -05:00
fe6ee5e51e closes #2
Add dynamic toggle options. Add toggle for turning on and off the autotune
2025-11-04 20:31:55 -05:00
cf0498a121 closes #1 2025-11-04 20:13:19 -05:00
f5245eb557 closes #7
Processor editor and processor in seperate files. slider paramters now can be added by simply adding them in the processor, everything else is dynamic
2025-11-04 20:04:07 -05:00
3468c1f389 autotune paramters, autotune in ui. UI organize 2025-11-01 13:33:14 -04:00
55e80b4c74 midi notes avaiable on ui 2025-10-30 21:39:06 -04:00
3645e38dd5 adjustable portamento, fixed adsr 2025-10-30 20:00:55 -04:00
098bd49cb5 better autotune speed 2025-10-30 19:49:58 -04:00
47 changed files with 4910 additions and 2045 deletions

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
"@fontsource/roboto": "^5.0.3",
"@mui/icons-material": "^5.13.7",
"@mui/material": "^5.13.7",
"@tailwindcss/postcss": "^4.1.17",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@ -44,8 +45,12 @@
]
},
"devDependencies": {
"autoprefixer": "^10.4.21",
"eslint": "^8.43.0",
"eslint-plugin-react": "^7.32.2",
"npm-build-zip": "^1.0.4"
"npm-build-zip": "^1.0.4",
"postcss": "^8.5.6",
"prettier": "^3.6.2",
"tailwindcss": "^3.4.18"
}
}

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Ladder Filter</title>
<title>Harmonizer</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,6 +1,6 @@
{
"short_name": "Ladder Filter",
"name": "Ladder Filter",
"short_name": "Harmonizer",
"name": "Harmonizer",
"icons": [
{
"src": "favicon.ico",

View File

@ -26,357 +26,17 @@ import "@fontsource/roboto/400.css";
import "@fontsource/roboto/500.css";
import "@fontsource/roboto/700.css";
import Box from "@mui/material/Container";
import Checkbox from "@mui/material/Checkbox";
import Typography from "@mui/material/Typography";
import Container from "@mui/material/Container";
import Slider from "@mui/material/Slider";
import Button from "@mui/material/Button";
import CardActions from "@mui/material/CardActions";
import Snackbar from "@mui/material/Snackbar";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select from "@mui/material/Select";
import FormGroup from "@mui/material/FormGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import { React, useState, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import * as Juce from "juce-framework-frontend";
import JuceSlider from "./Components/JuceSlider.js";
import JuceCheckbox from "./Components/JuceCheckbox.js";
import MidiNoteInfo from "./Components/MidiNoteInfo.js";
import AutoTuneInfo from "./Components/AutoTuneInfo.js";
import { controlParameterIndexAnnotation } from "./types/JuceTypes.js";
import { React } from "react";
import "./App.css";
// import { KnobPercentage } from "./Components/KnobPercentage";
// Custom attributes in React must be in all lower case
const controlParameterIndexAnnotation = "controlparameterindex";
function JuceSlider({ identifier, title }) {
JuceSlider.propTypes = {
identifier: PropTypes.string,
title: PropTypes.string,
};
const sliderState = Juce.getSliderState(identifier);
const [value, setValue] = useState(sliderState.getNormalisedValue());
const [properties, setProperties] = useState(sliderState.properties);
const handleChange = (event, newValue) => {
sliderState.setNormalisedValue(newValue);
setValue(newValue);
};
const mouseDown = () => {
sliderState.sliderDragStarted();
};
const changeCommitted = (event, newValue) => {
sliderState.setNormalisedValue(newValue);
sliderState.sliderDragEnded();
};
useEffect(() => {
const valueListenerId = sliderState.valueChangedEvent.addListener(() => {
setValue(sliderState.getNormalisedValue());
});
const propertiesListenerId = sliderState.propertiesChangedEvent.addListener(
() => setProperties(sliderState.properties)
);
return function cleanup() {
sliderState.valueChangedEvent.removeListener(valueListenerId);
sliderState.propertiesChangedEvent.removeListener(propertiesListenerId);
};
});
function calculateValue() {
return sliderState.getScaledValue();
}
return (
<Box
{...{
[controlParameterIndexAnnotation]:
sliderState.properties.parameterIndex,
}}
>
<Typography sx={{ mt: 1.5 }}>
{properties.name}: {sliderState.getScaledValue()} {properties.label}
</Typography>
<Slider
aria-label={title}
value={value}
scale={calculateValue}
onChange={handleChange}
min={0}
max={1}
step={1 / (properties.numSteps - 1)}
onChangeCommitted={changeCommitted}
onMouseDown={mouseDown}
/>
</Box>
);
}
function JuceCheckbox({ identifier }) {
JuceCheckbox.propTypes = {
identifier: PropTypes.string,
};
const checkboxState = Juce.getToggleState(identifier);
const [value, setValue] = useState(checkboxState.getValue());
const [properties, setProperties] = useState(checkboxState.properties);
const handleChange = (event) => {
checkboxState.setValue(event.target.checked);
setValue(event.target.checked);
};
useEffect(() => {
const valueListenerId = checkboxState.valueChangedEvent.addListener(() => {
setValue(checkboxState.getValue());
});
const propertiesListenerId =
checkboxState.propertiesChangedEvent.addListener(() =>
setProperties(checkboxState.properties)
);
return function cleanup() {
checkboxState.valueChangedEvent.removeListener(valueListenerId);
checkboxState.propertiesChangedEvent.removeListener(propertiesListenerId);
};
});
const cb = <Checkbox checked={value} onChange={handleChange} />;
return (
<Box
{...{
[controlParameterIndexAnnotation]:
checkboxState.properties.parameterIndex,
}}
>
<FormGroup>
<FormControlLabel control={cb} label={properties.name} />
</FormGroup>
</Box>
);
}
function JuceComboBox({ identifier }) {
JuceComboBox.propTypes = {
identifier: PropTypes.string,
};
const comboBoxState = Juce.getComboBoxState(identifier);
const [value, setValue] = useState(comboBoxState.getChoiceIndex());
const [properties, setProperties] = useState(comboBoxState.properties);
const handleChange = (event) => {
comboBoxState.setChoiceIndex(event.target.value);
setValue(event.target.value);
};
useEffect(() => {
const valueListenerId = comboBoxState.valueChangedEvent.addListener(() => {
setValue(comboBoxState.getChoiceIndex());
});
const propertiesListenerId =
comboBoxState.propertiesChangedEvent.addListener(() => {
setProperties(comboBoxState.properties);
});
return function cleanup() {
comboBoxState.valueChangedEvent.removeListener(valueListenerId);
comboBoxState.propertiesChangedEvent.removeListener(propertiesListenerId);
};
});
return (
<Box
{...{
[controlParameterIndexAnnotation]:
comboBoxState.properties.parameterIndex,
}}
>
<FormControl fullWidth>
<InputLabel id={identifier}>{properties.name}</InputLabel>
<Select
labelId={identifier}
value={value}
label={properties.name}
onChange={handleChange}
>
{properties.choices.map((choice, i) => (
<MenuItem value={i} key={i}>
{choice}
</MenuItem>
))}
</Select>
</FormControl>
</Box>
);
}
const sayHello = Juce.getNativeFunction("sayHello");
const SpectrumDataReceiver_eventId = "spectrumData";
function interpolate(a, b, s) {
let result = new Array(a.length).fill(0);
for (const [i, val] of a.entries()) result[i] += (1 - s) * val;
for (const [i, val] of b.entries()) result[i] += s * val;
return result;
}
function mod(dividend, divisor) {
const quotient = Math.floor(dividend / divisor);
return dividend - divisor * quotient;
}
class SpectrumDataReceiver {
constructor(bufferLength) {
this.bufferLength = bufferLength;
this.buffer = new Array(this.bufferLength);
this.readIndex = 0;
this.writeIndex = 0;
this.lastTimeStampMs = 0;
this.timeResolutionMs = 0;
let self = this;
this.spectrumDataRegistrationId = window.__JUCE__.backend.addEventListener(
SpectrumDataReceiver_eventId,
() => {
fetch(Juce.getBackendResourceAddress("spectrumData.json"))
.then((response) => response.text())
.then((text) => {
const data = JSON.parse(text);
if (self.timeResolutionMs == 0) {
self.timeResolutionMs = data.timeResolutionMs;
// We want to stay behind the write index by a full batch plus one
// so that we can keep reading buffered frames until we receive the
// new batch
self.readIndex = -data.frames.length - 1;
self.buffer.fill(new Array(data.frames[0].length).fill(0));
}
for (const f of data.frames)
self.buffer[mod(self.writeIndex++, self.bufferLength)] = f;
});
}
);
}
getBufferItem(index) {
return this.buffer[mod(index, this.buffer.length)];
}
getLevels(timeStampMs) {
if (this.timeResolutionMs == 0) return null;
const previousTimeStampMs = this.lastTimeStampMs;
this.lastTimeStampMs = timeStampMs;
if (previousTimeStampMs == 0) return this.buffer[0];
const timeAdvance =
(timeStampMs - previousTimeStampMs) / this.timeResolutionMs;
this.readIndex += timeAdvance;
const integralPart = Math.floor(this.readIndex);
const fractionalPart = this.readIndex - integralPart;
return interpolate(
this.getBufferItem(integralPart),
this.getBufferItem(integralPart + 1),
fractionalPart
);
}
unregister() {
window.__JUCE__.backend.removeEventListener(
this.spectrumDataRegistrationId
);
}
}
function FreqBandInfo() {
const canvasRef = useRef(null);
let dataReceiver = null;
let isActive = true;
// eslint-disable-next-line no-unused-vars
const render = (timeStampMs) => {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
var grd = ctx.createLinearGradient(0, 0, 0, canvas.height);
grd.addColorStop(0, "#1976d2");
grd.addColorStop(1, "#dae9f8");
ctx.fillStyle = grd;
if (dataReceiver != null) {
const levels = dataReceiver.getLevels(timeStampMs);
if (levels != null) {
const numBars = levels.length;
const barWidth = canvas.width / numBars;
const barHeight = canvas.height;
for (const [i, l] of levels.entries()) {
ctx.fillRect(
i * barWidth,
barHeight - l * barHeight,
barWidth,
l * barHeight
);
}
}
}
if (isActive) window.requestAnimationFrame(render);
};
useEffect(() => {
dataReceiver = new SpectrumDataReceiver(10);
isActive = true;
window.requestAnimationFrame(render);
return function cleanup() {
isActive = false;
dataReceiver.unregister();
};
});
const canvasStyle = {
marginLeft: "0",
marginRight: "0",
marginTop: "1em",
display: "block",
width: "94%",
bottom: "0",
position: "absolute",
};
return (
<Box>
<canvas height={90} style={canvasStyle} ref={canvasRef}></canvas>
</Box>
);
}
function App() {
const controlParameterIndexUpdater = new Juce.ControlParameterIndexUpdater(
@ -387,81 +47,80 @@ function App() {
controlParameterIndexUpdater.handleMouseMove(event);
});
const [open, setOpen] = useState(false);
const [snackbarMessage, setMessage] = useState("No message received yet");
const openSnackbar = () => {
setOpen(true);
};
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
const action = (
<>
<IconButton
size="small"
aria-label="close"
color="inherit"
onClick={handleClose}
>
<CloseIcon fontSize="small" />
</IconButton>
</>
);
return (
<div>
<Container>
<JuceSlider identifier="formantSlider" title="Formant" />
<JuceSlider identifier="autoTuneSpeedSlider" title="Auto Tune Speed" />
</Container>
<CardActions style={{ justifyContent: "center" }}>
<Button
variant="contained"
sx={{ marginTop: 2 }}
onClick={() => {
sayHello("JUCE").then((result) => {
setMessage(result);
openSnackbar();
});
}}
>
Call backend function
</Button>
</CardActions>
<CardActions style={{ justifyContent: "center" }}>
<Button
variant="contained"
sx={{ marginTop: 2 }}
onClick={() => {
fetch(Juce.getBackendResourceAddress("data.txt"))
.then((response) => response.text())
.then((text) => {
setMessage("Data fetched: " + text);
openSnackbar();
});
}}
>
Fetch data from backend
</Button>
</CardActions>
<JuceCheckbox identifier="muteToggle" />
<br></br>
<JuceComboBox identifier="filterTypeCombo" />
<FreqBandInfo></FreqBandInfo>
<Snackbar
open={open}
autoHideDuration={6000}
onClose={handleClose}
message={snackbarMessage}
action={action}
/>
<div className="min-h-screen bg-[#0f0f0f] p-4 relative overflow-hidden">
{/* Controls Grid */}
<div className="grid grid-cols-3 gap-2 items-start">
{/* Left Column */}
<div className="border border-[#2a2a2a] rounded-lg p-4">
<div className="flex flex-col gap-4">
<div className="flex items-center justify-center">
<div>
<JuceSlider identifier="harmonyMix" title="Mix" />
</div>
<div>
<JuceSlider identifier="formantPreserve" title="Formant" />
</div>
</div>
<div className="flex items-center justify-center mt-[45px]">
<div>
<JuceSlider identifier="portTime" title="Portamento Speed" />
</div>
<div>
<JuceSlider identifier="panWidth" title="Pan Width" />
</div>
</div>
</div>
</div>
<div className="border border-[#2a2a2a] rounded-lg p-4">
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-2 items-center">
<div className="self-center justify-center items-center flex">
<JuceCheckbox identifier="autoTuneEnabled" />
</div>
<div className="mt-0 w-full">
<AutoTuneInfo />
</div>
</div>
<div className="grid grid-cols-2 grid-rows-1 gap-4">
<div>
<JuceSlider
identifier="autoTuneSpeed"
title="Auto Tune Speed"
/>
</div>
<div>
<JuceSlider
identifier="autoTuneDepth"
title="Auto Tune Depth"
/>
</div>
</div>
</div>
</div>
<div className="border border-[#2a2a2a] rounded-lg p-4">
<div className="flex flex-col gap-4 items-center justify-center">
<div className="mt-0 pt-0 flex items-center justify-center ">
<JuceCheckbox identifier="freezeEnabled" />
</div>
<div className="flex items-center justify-center mt-[100px]">
<div>
<JuceSlider identifier="freezePitch" title="Freeze Pitch" />
</div>
<div>
<JuceSlider identifier="freezeVolume" title="Freeze Volume" />
</div>
</div>
</div>
</div>
</div>
<Container></Container>
<div className="rounded-lg">
<MidiNoteInfo />
</div>
</div>
);
}

1
Assets/web/src/Colors.js Normal file
View File

@ -0,0 +1 @@
export const HIGHLIGHT_COLOR = "#5242cdff";

View File

@ -0,0 +1,133 @@
/* eslint-disable no-unused-vars */
import React, { useState, useEffect, useRef } from "react";
import CenterGrowSlider from "./CenterGrowSlider.js";
import AutoTuneDataReceiver from "../DataRecievers/AutoTuneDataReceiver.js";
import PianoKeyboard from "./PianoKeyboard.js";
// import { Slider } from "@mui/material";
// import { styled } from "@mui/material/styles";
// eslint-disable-next-line react/prop-types
export default function AutoTuneInfo() {
const [inputCents, setInputCents] = useState(0);
const [outputCents, setOutputCents] = useState(0);
const [autotuneNote, setAutotuneNote] = useState(0);
const [showPopup, setShowPopup] = useState(false);
const [autoTuneKey, setAutoTuneKey] = useState("");
const dataReceiverRef = useRef(null);
const isActiveRef = useRef(true);
function getCharfromNoteIndex(index) {
if (index === -1) return "-";
const NOTE_NAMES = [
"C",
"C♯",
"D",
"D♯",
"E",
"F",
"F♯",
"G",
"G♯",
"A",
"A♯",
"B",
];
if (typeof index !== "number" || isNaN(index)) return "";
return NOTE_NAMES[index % NOTE_NAMES.length];
}
useEffect(() => {
dataReceiverRef.current = new AutoTuneDataReceiver();
isActiveRef.current = true;
function render() {
if (!isActiveRef.current) return;
if (dataReceiverRef.current) {
setInputCents(dataReceiverRef.current.getInputCents());
setOutputCents(dataReceiverRef.current.getOutputCents());
setAutotuneNote(dataReceiverRef.current.getAutotuneNote());
}
window.requestAnimationFrame(render);
}
window.requestAnimationFrame(render);
return function cleanup() {
isActiveRef.current = false;
if (dataReceiverRef.current) dataReceiverRef.current.unregister();
};
}, []);
return (
<div className="p-0 flex flex-col gap-1">
<div className="flex">
<h1
className="w-8 flex-initial py-2 px-1 text-xl"
style={{ color: "#666" }}
>
{getCharfromNoteIndex(autotuneNote)}
</h1>
<div className=" py-2 px-1 flex-1">
<div className="py-1">
<CenterGrowSlider value={inputCents} />
</div>
<div className="py-1">
<CenterGrowSlider value={outputCents} />
</div>
</div>
</div>
<div className="flex justify-start items-center">
<select
value={autoTuneKey}
className="select-none w-10 h-10 rounded px-2 bg-[#262626] text-[#eee]"
onChange={(e) => {
//send stuff to plugin here
setAutoTuneKey("");
}}
aria-label="Select note"
style={{
appearance: "none",
WebkitAppearance: "none",
textAlign: "center",
border: "none",
outline: "none",
}}
>
<option value="" disabled hidden style={{ textAlign: "center" }}>
...
</option>
{[
"C",
"C♯",
"D",
"D♯",
"E",
"F",
"F♯",
"G",
"G♯",
"A",
"A♯",
"B",
].map((key, idx) => (
<option
key={key}
value={idx}
style={{ textAlign: "start", border: "none", outline: "none" }}
>
{key}
</option>
))}
</select>
<div className="h-[40px] w-[85%] self-end px-1">
<PianoKeyboard
heldNotes={[]}
LOWEST_MIDI={0}
HIGHEST_MIDI={11}
showNoteNames={false}
/>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,58 @@
/* eslint-disable react/prop-types */
import React from "react";
export default function CenterGrowSlider({
value,
min = -50,
max = 50,
backgroundColor = "rgba(150,150,150,0.3)",
height = 8,
}) {
// Clamp the value
const clamped = Math.max(min, Math.min(max, value));
const range = max - min;
const halfRange = range / 2;
const magnitude = Math.abs(clamped) / halfRange; // 0..1
// Calculate widths (each bar maxes out at 50% width)
const positiveWidth = clamped > 0 ? magnitude * 50 : 0;
const negativeWidth = clamped < 0 ? magnitude * 50 : 0;
const baseStyle = {
position: "absolute",
top: "50%",
height: `${height}px`,
transform: "translateY(-50%)",
};
return (
<div
style={{
position: "relative",
width: "100%",
height: `${height}px`,
backgroundColor,
overflow: "hidden",
}}
>
{/* Negative (left) bar */}
<div
className="bg-primary shadow-primary/40 shadow-[0_0_16px,inset_0_1px_2px_rgba(255,255,255,0.3)]"
style={{
...baseStyle,
right: "50%", // anchored to the center
width: `${negativeWidth}%`,
}}
/>
{/* Positive (right) bar */}
<div
className="bg-primary shadow-primary/40 shadow-[0_0_16px,inset_0_1px_2px_rgba(255,255,255,0.3)]"
style={{
...baseStyle,
left: "50%", // anchored to the center
width: `${positiveWidth}%`,
}}
/>
</div>
);
}

View File

@ -0,0 +1,89 @@
/* eslint-disable react/prop-types */
import React, { useState, useRef, useEffect } from "react";
import { HIGHLIGHT_COLOR } from "../Colors.js";
export function HorizontalSlider({
value = 50,
onChange,
min = 0,
max = 100,
showFill = false,
}) {
// const [localValue, setLocalValue] = useState(value);
const [percentage, setPercentage] = useState(
((value - min) / (max - min)) * 100
);
const sliderRef = useRef(null);
const isDragging = useRef(false);
useEffect(() => {
setPercentage(((value - min) / (max - min)) * 100);
}, [value, min, max]);
const handleMouseDown = (e) => {
isDragging.current = true;
updateValue(e.clientX);
e.preventDefault();
};
const updateValue = (clientX) => {
if (!sliderRef.current) return;
const rect = sliderRef.current.getBoundingClientRect();
const percentage = Math.max(
0,
Math.min(100, ((clientX - rect.left) / rect.width) * 100)
);
const newValue = min + (percentage / 100) * (max - min);
// setLocalValue(newValue);
onChange?.(newValue);
};
useEffect(() => {
const handleMouseMove = (e) => {
if (!isDragging.current) return;
updateValue(e.clientX);
};
const handleMouseUp = () => {
isDragging.current = false;
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
}, []);
return (
<div className="relative w-64 h-10">
<div
ref={sliderRef}
className="absolute top-1/2 -translate-y-1/2 w-full h-8 bg-[#1a1a1a] border-2 border-[#2a2a2a] rounded-full cursor-pointer select-none shadow-[inset_0_2px_8px_rgba(0,0,0,0.5),inset_0_-1px_3px_rgba(255,255,255,0.03)] overflow-hidden"
onMouseDown={handleMouseDown}
>
{/* Diffused top highlight for track */}
<div className="absolute -top-1 left-0 right-0 h-3/4 bg-gradient-to-b from-white/[0.06] via-white/[0.015] to-transparent rounded-full pointer-events-none blur-[2px]" />
{showFill && (
<div
className={`absolute left-0 top-0 h-full bg-primary rounded-full shadow-primary/40 shadow-[0_0_8px]`}
style={{ width: `${percentage}%` }}
/>
)}
</div>
{/* Thumb outside the track container */}
<div
className="absolute top-1/2 -translate-y-1/2 w-10 h-10 bg-[#2a2a2a] border-2 border-[#3a3a3a] rounded-full shadow-[0_4px_8px_rgba(0,0,0,0.4),inset_0_-1px_4px_rgba(255,255,255,0.05),inset_0_2px_4px_rgba(0,0,0,0.3)] overflow-hidden pointer-events-none"
style={{ left: `calc(${percentage}% - 20px)` }}
>
<div className="absolute -top-1 left-0 right-0 h-3/4 bg-gradient-to-b from-white/[0.08] via-white/[0.02] to-transparent rounded-full pointer-events-none blur-[2px]" />
</div>
</div>
);
}

View File

@ -0,0 +1,91 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import Box from "@mui/material/Box";
import * as Juce from "juce-framework-frontend";
// import Checkbox from "@mui/material/Checkbox";
// import FormGroup from "@mui/material/FormGroup";
// import FormControlLabel from "@mui/material/FormControlLabel";
import { controlParameterIndexAnnotation } from "../types/JuceTypes.js";
// import { ToggleSwitch } from "./ToggleSwitch.js";
export default function JuceCheckbox({ identifier }) {
JuceCheckbox.propTypes = {
identifier: PropTypes.string,
};
const checkboxState = Juce.getToggleState(identifier);
const [value, setValue] = useState(checkboxState.getValue());
// eslint-disable-next-line no-unused-vars
const [properties, setProperties] = useState(checkboxState.properties);
// const handleChange = (event) => {
// checkboxState.setValue(event.target.checked);
// setValue(event.target.checked);
// };
const handleChange = (value) => {
checkboxState.setValue(value);
setValue(value);
};
useEffect(() => {
const valueListenerId = checkboxState.valueChangedEvent.addListener(() => {
setValue(checkboxState.getValue());
});
const propertiesListenerId =
checkboxState.propertiesChangedEvent.addListener(() =>
setProperties(checkboxState.properties)
);
return function cleanup() {
checkboxState.valueChangedEvent.removeListener(valueListenerId);
checkboxState.propertiesChangedEvent.removeListener(propertiesListenerId);
};
});
// const cb = <Checkbox checked={value} onChange={handleChange} />;
// const cb = <ToggleSwitch value={value} onChange={handleChange} />;
return (
<Box
margin={0}
padding={0}
{...{
[controlParameterIndexAnnotation]:
checkboxState.properties.parameterIndex,
}}
>
<div className="flex gap-2">
<button
onClick={() => handleChange(true)}
className={`px-8 py-3 rounded transition-colors transition-shadow relative overflow-hidden ${
value
? `bg-primary text-[#1a1a1a] shadow-primary/40 shadow-[0_0_16px,inset_0_1px_2px_rgba(255,255,255,0.3)]`
: `bg-[#1a1a1a] text-primary border-2 border-[#2a2a2a] shadow-[inset_0_2px_4px_rgba(0,0,0,0.3)]`
}`}
>
{!value && (
<div className="absolute -top-1/4 left-0 right-0 h-3/4 bg-gradient-to-b from-white/[0.08] via-white/[0.02] to-transparent pointer-events-none blur-[2px]" />
)}
<span className="relative z-10">ON</span>
</button>
<button
onClick={() => handleChange(false)}
className={`px-8 py-3 rounded transition-colors transition-shadow relative overflow-hidden ${
!value
? `bg-primary text-[#1a1a1a] shadow-primary/40 shadow-[0_0_16px,inset_0_1px_2px_rgba(255,255,255,0.3)]`
: `bg-[#1a1a1a] text-primary border-2 border-[#2a2a2a] shadow-[inset_0_2px_4px_rgba(0,0,0,0.3)]`
}`}
>
{value && (
<div className="absolute -top-1/4 left-0 right-0 h-3/4 bg-gradient-to-b from-white/[0.08] via-white/[0.02] to-transparent pointer-events-none blur-[2px]" />
)}
<span className="relative z-10">OFF</span>
</button>
</div>
{/* <ToggleSwitch value={value} onChange={handleChange} /> */}
{/* <FormGroup>
<FormControlLabel control={cb} />
</FormGroup> */}
</Box>
);
}

View File

@ -0,0 +1,64 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import Box from "@mui/material/Box";
import * as Juce from "juce-framework-frontend";
import Select from "@mui/material/Select";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import { controlParameterIndexAnnotation } from "../types/JuceTypes.js";
export default function JuceComboBox({ identifier }) {
JuceComboBox.propTypes = {
identifier: PropTypes.string,
};
const comboBoxState = Juce.getComboBoxState(identifier);
const [value, setValue] = useState(comboBoxState.getChoiceIndex());
const [properties, setProperties] = useState(comboBoxState.properties);
const handleChange = (event) => {
comboBoxState.setChoiceIndex(event.target.value);
setValue(event.target.value);
};
useEffect(() => {
const valueListenerId = comboBoxState.valueChangedEvent.addListener(() => {
setValue(comboBoxState.getChoiceIndex());
});
const propertiesListenerId =
comboBoxState.propertiesChangedEvent.addListener(() => {
setProperties(comboBoxState.properties);
});
return function cleanup() {
comboBoxState.valueChangedEvent.removeListener(valueListenerId);
comboBoxState.propertiesChangedEvent.removeListener(propertiesListenerId);
};
});
return (
<Box
{...{
[controlParameterIndexAnnotation]:
comboBoxState.properties.parameterIndex,
}}
>
<FormControl fullWidth>
<InputLabel id={identifier}>{properties.name}</InputLabel>
<Select
labelId={identifier}
value={value}
label={properties.name}
onChange={handleChange}
>
{properties.choices.map((choice, i) => (
<MenuItem value={i} key={i}>
{choice}
</MenuItem>
))}
</Select>
</FormControl>
</Box>
);
}

View File

@ -0,0 +1,93 @@
import PropTypes from "prop-types";
import Box from "@mui/material/Container";
import Typography from "@mui/material/Typography";
// import Slider from "@mui/material/Slider";
import * as Juce from "juce-framework-frontend";
import { React, useState, useEffect } from "react";
import { controlParameterIndexAnnotation } from "../types/JuceTypes.js";
import { Knob } from "./knob.js";
// import { HorizontalSlider } from "./HorizontalSlider.js";
export default function JuceSlider({ identifier }) {
JuceSlider.propTypes = {
identifier: PropTypes.string,
};
const sliderState = Juce.getSliderState(identifier);
const [value, setValue] = useState(sliderState.getNormalisedValue());
const [properties, setProperties] = useState(sliderState.properties);
const handleChange = (newValue) => {
sliderState.setNormalisedValue(newValue);
setValue(newValue);
};
// const mouseDown = () => {
// sliderState.sliderDragStarted();
// };
// const changeCommitted = (event, newValue) => {
// sliderState.setNormalisedValue(newValue);
// sliderState.sliderDragEnded();
// };
useEffect(() => {
const valueListenerId = sliderState.valueChangedEvent.addListener(() => {
setValue(sliderState.getNormalisedValue());
});
const propertiesListenerId = sliderState.propertiesChangedEvent.addListener(
() => setProperties(sliderState.properties)
);
return function cleanup() {
sliderState.valueChangedEvent.removeListener(valueListenerId);
sliderState.propertiesChangedEvent.removeListener(propertiesListenerId);
};
});
// function calculateValue() {
// return sliderState.getScaledValue();
// }
return (
<Box
{...{
[controlParameterIndexAnnotation]:
sliderState.properties.parameterIndex,
}}
>
<div className="justify-items-center">
<Typography
m={0}
p={0}
fontSize={14}
className="text-[#666666] text-center"
>
{properties.name}
{properties.label}
</Typography>
<Knob value={value} onChange={handleChange} min={0} max={1} size="sm" />
{/* <HorizontalSlider
value={value}
onChange={handleChange}
min={0}
max={1}
showFill
/>
<Slider
aria-label={title}
value={value}
scale={calculateValue}
// onChange={handleChange}
min={0}
max={1}
step={1 / (properties.numSteps - 1)}
onChangeCommitted={changeCommitted}
onMouseDown={mouseDown}
/> */}
</div>
</Box>
);
}

View File

@ -1,88 +0,0 @@
import clsx from "clsx";
import { useId, useState, React } from "react";
import {
KnobHeadless,
KnobHeadlessLabel,
KnobHeadlessOutput,
useKnobKeyboardControls,
} from "react-knob-headless";
import { mapFrom01Linear, mapTo01Linear } from "@dsp-ts/math";
import { KnobBaseThumb } from "./KnobBaseThumb";
export function KnobBase({
theme,
label,
valueDefault,
valueMin,
valueMax,
valueRawRoundFn,
valueRawDisplayFn,
axis,
stepFn,
stepLargerFn,
mapTo01 = mapTo01Linear,
mapFrom01 = mapFrom01Linear,
}) {
KnobBase.propTypes = {
theme: KnobBase.string,
label: KnobBase.string,
valueDefault: KnobBase.number,
valueMin: KnobBase.number,
valueMax: KnobBase.number,
valueRawRoundFn: KnobBase.func,
valueRawDisplayFn: KnobBase.func,
axis: KnobBase.string,
stepFn: KnobBase.func,
stepLargerFn: KnobBase.func,
mapTo01: KnobBase.func,
mapFrom01: KnobBase.func,
};
const knobId = useId();
const labelId = useId();
const [valueRaw, setValueRaw] = useState(valueDefault);
const value01 = mapTo01(valueRaw, valueMin, valueMax);
const step = stepFn(valueRaw);
const stepLarger = stepLargerFn(valueRaw);
const dragSensitivity = 0.006;
const keyboardControlHandlers = useKnobKeyboardControls({
valueRaw,
valueMin,
valueMax,
step,
stepLarger,
onValueRawChange: setValueRaw,
});
return (
<div
className={clsx(
"w-16 flex flex-col gap-0.5 justify-center items-center text-xs select-none",
"outline-none focus-within:outline-1 focus-within:outline-offset-4 focus-within:outline-stone-300"
)}
>
<KnobHeadlessLabel id={labelId}>{label}</KnobHeadlessLabel>
<KnobHeadless
id={knobId}
aria-labelledby={labelId}
className="relative w-16 h-16 outline-none"
valueMin={valueMin}
valueMax={valueMax}
valueRaw={valueRaw}
valueRawRoundFn={valueRawRoundFn}
valueRawDisplayFn={valueRawDisplayFn}
dragSensitivity={dragSensitivity}
axis={axis}
mapTo01={mapTo01}
mapFrom01={mapFrom01}
onValueRawChange={setValueRaw}
{...keyboardControlHandlers}
>
<KnobBaseThumb theme={theme} value01={value01} />
</KnobHeadless>
<KnobHeadlessOutput htmlFor={knobId}>
{valueRawDisplayFn(valueRaw)}
</KnobHeadlessOutput>
</div>
);
}

View File

@ -1,28 +0,0 @@
import clsx from "clsx";
import { mapFrom01Linear } from "@dsp-ts/math";
import { React } from "react";
export function KnobBaseThumb({ theme, value01 }) {
KnobBaseThumb.propTypes = {
theme: KnobBaseThumb.string,
value01: KnobBaseThumb.number,
};
const angleMin = -145;
const angleMax = 145;
const angle = mapFrom01Linear(value01, angleMin, angleMax);
return (
<div
className={clsx(
"absolute h-full w-full rounded-full",
theme === "stone" && "bg-stone-300",
theme === "pink" && "bg-pink-300",
theme === "green" && "bg-green-300",
theme === "sky" && "bg-sky-300"
)}
>
<div className="absolute h-full w-full" style={{ rotate: `${angle}deg` }}>
<div className="absolute left-1/2 top-0 h-1/2 w-[2px] -translate-x-1/2 rounded-sm bg-stone-950" />
</div>
</div>
);
}

View File

@ -1,33 +0,0 @@
"use client";
import { KnobBase } from "./KnobBase";
import { React } from "react";
export function KnobPercentage({ theme, label, axis }) {
KnobPercentage.propTypes = {
theme: KnobPercentage.string,
label: KnobPercentage.string,
axis: KnobPercentage.string,
};
return (
<KnobBase
valueDefault={valueDefault}
valueMin={valueMin}
valueMax={valueMax}
stepFn={stepFn}
stepLargerFn={stepLargerFn}
valueRawRoundFn={valueRawRoundFn}
valueRawDisplayFn={valueRawDisplayFn}
theme={theme}
label={label}
axis={axis}
/>
);
}
const valueMin = 0;
const valueMax = 100;
const valueDefault = 50;
const stepFn = (valueRaw) => 1;
const stepLargerFn = (valueRaw) => 10;
const valueRawRoundFn = Math.round;
const valueRawDisplayFn = (valueRaw) => `${valueRawRoundFn(valueRaw)}%`;

View File

@ -0,0 +1,38 @@
import React, { useState, useEffect, useRef } from "react";
import PianoKeyboard from "./PianoKeyboard";
import MidNoteDataReceiver from "../DataRecievers/MidiNoteDataReceiver.js";
// import { Slider } from "@mui/material";
// import { styled } from "@mui/material/styles";
// eslint-disable-next-line react/prop-types
export default function MidiNoteInfo() {
const [notes, setNotes] = useState([]);
const dataReceiverRef = useRef(null);
const isActiveRef = useRef(true);
useEffect(() => {
dataReceiverRef.current = new MidNoteDataReceiver();
isActiveRef.current = true;
function render() {
if (!isActiveRef.current) return;
if (dataReceiverRef.current) {
setNotes(dataReceiverRef.current.getNotes());
}
window.requestAnimationFrame(render);
}
window.requestAnimationFrame(render);
return function cleanup() {
isActiveRef.current = false;
if (dataReceiverRef.current) dataReceiverRef.current.unregister();
};
}, []);
return (
<div className="rounded-lg h-[80px]" style={{ marginTop: "1rem" }}>
<PianoKeyboard heldNotes={notes} LOWEST_MIDI={24} HIGHEST_MIDI={84} />
</div>
);
}

View File

@ -0,0 +1,219 @@
/* eslint-disable react/prop-types */
import React /*, { useRef, useEffect, useState }*/ from "react";
const NOTE_NAMES = [
"C",
"C♯",
"D",
"D♯",
"E",
"F",
"F♯",
"G",
"G♯",
"A",
"A♯",
"B",
];
const WHITE_KEYS = [0, 2, 4, 5, 7, 9, 11];
// C2 = 36, C5 = 72
// const LOWEST_MIDI = 24;
// const HIGHEST_MIDI = 84;
function getNoteName(midi) {
const octave = Math.floor(midi / 12) - 1;
const note = NOTE_NAMES[midi % 12];
return `${note}${octave}`;
}
function isWhiteKey(midi) {
return WHITE_KEYS.includes(midi % 12);
}
export default function PianoKeyboard({
heldNotes,
LOWEST_MIDI,
HIGHEST_MIDI,
showNoteNames = true,
}) {
const heldMap = {};
heldNotes.forEach((n) => (heldMap[n.midi] = n.voice));
const keys = [];
for (let midi = LOWEST_MIDI; midi <= HIGHEST_MIDI; midi++) {
const white = isWhiteKey(midi);
const held = heldMap[midi] !== undefined;
keys.push({
midi,
white,
held,
voice: heldMap[midi],
noteName: getNoteName(midi),
});
}
const whiteKeys = keys.filter((k) => k.white);
const blackKeys = keys.filter((k) => !k.white);
// For responsive black key positioning
const numWhite = whiteKeys.length;
// Map midi to white key index for black key positioning
const midiToWhiteIndex = {};
let whiteIdx = 0;
for (let midi = LOWEST_MIDI; midi <= HIGHEST_MIDI; midi++) {
if (isWhiteKey(midi)) {
midiToWhiteIndex[midi] = whiteIdx++;
}
}
// For each black key, find its position between white keys
function getBlackKeyPercent(midi) {
// Black keys are always after a white key except for the first key
// For example, C# is between C and D
// So, find the previous white key index, then add ~0.65 of a white key width
const prevWhite = midi - 1;
const idx = midiToWhiteIndex[prevWhite];
if (idx === undefined) return 0;
// Offset: (idx + 0.65) / numWhite * 100%
return ((idx + 1) / numWhite) * 100;
}
return (
<div
style={{
position: "relative",
height: "100%",
userSelect: "none",
width: "100%",
margin: "0 auto",
}}
>
{/* White keys */}
<div
style={{
display: "flex",
position: "relative",
zIndex: 1,
height: "100%",
}}
>
{whiteKeys.map((k, i) => (
<div
key={k.midi}
className={
k.held
? "bg-primary shadow-primary/30 shadow-[0_0_16px,inset_0_1px_2px_rgba(255,255,255,0.2)]"
: "bg-[#222]"
}
style={{
flex: "1 1 0",
height: "100%",
border: "1px solid #2a2a2a",
position: "relative",
boxSizing: "border-box",
marginRight: -1,
display: "flex",
flexDirection: "column-reverse",
alignItems: "center",
justifyContent: "flex-start",
fontSize: 10,
fontFamily: "monospace",
overflow: "hidden",
borderTopLeftRadius: i === 0 ? 6 : 0, // round left edge of first key
borderBottomLeftRadius: i === 0 ? 6 : 0,
borderTopRightRadius: i === whiteKeys.length - 1 ? 6 : 0, // round right edge of last key
borderBottomRightRadius: i === whiteKeys.length - 1 ? 6 : 0,
}}
>
{showNoteNames && (
<div
style={{
display: "flex",
flexDirection: "column-reverse",
alignItems: "center",
}}
>
<span style={{ color: "#555" }}>{k.noteName}</span>
{k.held && (
<span
style={{
color: "#666666",
fontWeight: "bold",
fontSize: 14,
lineHeight: "14px",
marginBottom: 2,
}}
>
{k.voice}
</span>
)}
</div>
)}
</div>
))}
</div>
{/* Black keys */}
<div
style={{
position: "absolute",
top: 0,
left: 0,
height: "62%",
width: "100%",
zIndex: 2,
pointerEvents: "none",
}}
>
{blackKeys.map((k) => (
<div
key={k.midi}
className={
k.held
? "bg-primary shadow-primary/30 shadow-[0_0_16px,inset_0_1px_2px_rgba(255,255,255,0.2)]"
: "bg-[#111]"
}
style={{
position: "absolute",
left: `${getBlackKeyPercent(k.midi)}%`,
width: `${(100 / numWhite) * 0.65}%`,
height: "100%",
border: "1px solid #333",
borderRadius: 3,
display: "flex",
flexDirection: "column-reverse",
alignItems: "center",
justifyContent: "flex-start",
fontSize: 10,
fontFamily: "monospace",
boxSizing: "border-box",
transform: "translateX(-50%)",
}}
>
<div
style={{
display: "flex",
flexDirection: "column-reverse",
alignItems: "center",
}}
>
{k.held && (
<span
style={{
color: "#666666",
fontWeight: "bold",
fontSize: 14,
lineHeight: "14px",
marginBottom: 2,
}}
>
{k.voice}
</span>
)}
</div>
</div>
))}
</div>
</div>
);
}

View File

@ -0,0 +1,94 @@
/* eslint-disable react/prop-types */
import React, { useState, useRef, useEffect } from "react";
// interface KnobProps {
// value?: number;
// onChange?: (value: number) => void;
// min?: number;
// max?: number;
// size?: 'sm' | 'md' | 'lg';
// }
export function Knob({ value = 0, onChange, min = 0, max = 100, size = "md" }) {
// const [localValue, setLocalValue] = useState(value);
const isDragging = useRef(false);
const startX = useRef(0);
const startY = useRef(0);
const startValue = useRef(0);
const sizeClasses = {
sm: "w-16 h-16",
md: "w-24 h-24",
lg: "w-32 h-32",
};
const dotSize = {
sm: "w-2 h-2",
md: "w-2.5 h-2.5",
lg: "w-3 h-3",
};
const [rotation, setRotation] = useState(
((value - min) / (max - min)) * 270 - 135
);
const handleMouseDown = (e) => {
isDragging.current = true;
startX.current = e.clientX;
startY.current = e.clientY;
startValue.current = value;
e.preventDefault();
};
useEffect(() => {
const handleMouseMove = (e) => {
if (!isDragging.current) return;
const deltaX = e.clientX - startX.current;
const deltaY = startY.current - e.clientY;
const combinedDelta = deltaX + deltaY;
const sensitivity = 0.01;
const newValue = Math.max(
min,
Math.min(max, startValue.current + combinedDelta * sensitivity)
);
setRotation(((newValue - min) / (max - min)) * 270 - 135);
onChange?.(newValue);
};
const handleMouseUp = () => {
isDragging.current = false;
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
}, [min, max, onChange]);
useEffect(() => {
setRotation(((value - min) / (max - min)) * 270 - 135);
}, [value, min, max]);
return (
<div
className={`${sizeClasses[size]} rounded-full bg-[#1a1a1a] border-2 border-[#2a2a2a] relative cursor-pointer select-none shadow-[inset_0_2px_8px_rgba(0,0,0,0.5),inset_0_-2px_6px_rgba(255,255,255,0.03),0_4px_12px_rgba(0,0,0,0.4)] overflow-hidden`}
onMouseDown={handleMouseDown}
>
{/* Diffused top highlight */}
<div className="absolute -top-1/4 left-0 right-0 h-3/4 bg-gradient-to-b from-white/[0.08] via-white/[0.02] to-transparent rounded-full pointer-events-none blur-sm" />
<div
className="absolute inset-0 flex items-start justify-center pt-2"
style={{ transform: `rotate(${rotation}deg)` }}
>
<div
className={`${dotSize[size]} rounded-full bg-primary shadow-primary/90 shadow-[0_0_12px]`}
/>
</div>
</div>
);
}

View File

@ -0,0 +1,42 @@
// import * as Juce from "juce-framework-frontend";
// import reportWebVitals from "../reportWebVitals";
const AutoTuneDataReceiver_eventId = "autoTuneData";
export default class AutoTuneDataReceiver {
constructor() {
this.input_pitch = 0;
this.output_pitch = 0;
let self = this;
this.autoTuneDataRegistrationId = window.__JUCE__.backend.addEventListener(
AutoTuneDataReceiver_eventId,
(event) => {
self.input_pitch = event.input_pitch;
self.output_pitch = event.output_pitch;
}
);
}
frequencytoMidi(frequency) {
return 69 + 12 * Math.log2(frequency / 440);
}
getAutotuneNote() {
if (this.output_pitch <= 0) return -1;
const midi = this.frequencytoMidi(this.output_pitch);
return Math.round(midi % 12);
}
getInputCents() {
const midi = this.frequencytoMidi(this.input_pitch);
return Math.round((midi - Math.round(midi)) * 100);
}
getOutputCents() {
const midi = this.frequencytoMidi(this.output_pitch);
return Math.round((midi - Math.round(midi)) * 100);
}
unregister() {
window.__JUCE__.backend.removeEventListener(
this.autoTuneDataRegistrationId
);
}
}

View File

@ -0,0 +1,26 @@
// import * as Juce from "juce-framework-frontend";
// import reportWebVitals from "../reportWebVitals";
const MidNoteDataReceiver_eventId = "midNoteData";
export default class MidNoteDataReceiver {
constructor() {
this.notes = [];
this.input_pitch = 0;
this.output_pitch = 0;
let self = this;
this.midNoteDataRegistrationId = window.__JUCE__.backend.addEventListener(
MidNoteDataReceiver_eventId,
(event) => {
self.notes = event.notes;
}
);
}
getNotes() {
return this.notes;
}
unregister() {
window.__JUCE__.backend.removeEventListener(this.midNoteDataRegistrationId);
}
}

View File

@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
@ -12,3 +16,201 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
@custom-variant dark (&:is(.dark *));
:root {
--font-size: 16px;
--background: #ffffff;
--foreground: oklch(0.145 0 0);
--card: #ffffff;
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: #030213;
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.95 0.0058 264.53);
--secondary-foreground: #030213;
--muted: #ececf0;
--muted-foreground: #717182;
--accent: #e9ebef;
--accent-foreground: #030213;
--destructive: #d4183d;
--destructive-foreground: #ffffff;
--border: rgba(0, 0, 0, 0.1);
--input: transparent;
--input-background: #f3f3f5;
--switch-background: #cbced4;
--font-weight-medium: 500;
--font-weight-normal: 400;
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: #030213;
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.145 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.145 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.269 0 0);
--input: oklch(0.269 0 0);
--ring: oklch(0.439 0 0);
--font-weight-medium: 500;
--font-weight-normal: 400;
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(0.269 0 0);
--sidebar-ring: oklch(0.439 0 0);
--color-primary-rgb: 127,255,127;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-input-background: var(--input-background);
--color-switch-background: var(--switch-background);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
@layer base {
/* * {
@apply border-border outline-ring/50;
} */
/* body {
@apply bg-background text-foreground;
} */
}
/**
* Base typography. This is not applied to elements which have an ancestor with a Tailwind text class.
*/
@layer base {
:where(:not(:has([class*=' text-']), :not(:has([class^='text-'])))) {
h1 {
font-size: var(--text-2xl);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
h2 {
font-size: var(--text-xl);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
h3 {
font-size: var(--text-lg);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
h4 {
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
p {
font-size: var(--text-base);
font-weight: var(--font-weight-normal);
line-height: 1.5;
}
label {
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
button {
font-size: var(--text-base);
font-weight: var(--font-weight-medium);
line-height: 1.5;
}
input {
font-size: var(--text-base);
font-weight: var(--font-weight-normal);
line-height: 1.5;
}
}
}
html {
font-size: var(--font-size);
}
@layer utilities {
.bg-gradient-radial {
background-image: radial-gradient(circle, var(--tw-gradient-stops));
}
}

View File

@ -25,7 +25,7 @@ import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import reportWebVitals from "./reportWebVitals.js";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(

View File

@ -21,9 +21,9 @@
==============================================================================
*/
const reportWebVitals = onPerfEntry => {
const reportWebVitals = (onPerfEntry) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);

View File

@ -0,0 +1 @@
export const controlParameterIndexAnnotation = "controlparameterindex";

View File

@ -0,0 +1,13 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/*.{js,jsx,ts,tsx}", "./src/**/*.{js,jsx,ts,tsx}"],
theme: {
extend: {
colors: {
//primary: "#7FFF7F",
primary: "#2ccaffff",
},
},
},
plugins: [],
};

Binary file not shown.

View File

@ -67,7 +67,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -81,7 +81,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -97,6 +97,10 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>$(IntDir)\Harmonizer.bsc</OutputFile>
</Bscmake>
<PostBuildEvent>
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Debug\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
@ -109,7 +113,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -123,7 +127,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;JUCE_SHARED_CODE=1;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -142,8 +146,18 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>$(IntDir)\Harmonizer.bsc</OutputFile>
</Bscmake>
<PreBuildEvent>
<Command>cmd /c &quot;(cd /d ..\..\Assets\web &amp;&amp; npm run build &amp;&amp; npm run zip)&quot;
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Release\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\Source\PluginEditor.cpp"/>
<ClCompile Include="..\..\Source\PluginProcessor.cpp"/>
<ClCompile Include="..\..\Source\shifter_voice.cpp"/>
<ClCompile Include="..\..\Source\adsr.cpp"/>
<ClCompile Include="..\..\Source\port.cpp"/>
@ -2830,100 +2844,100 @@
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_basics\juce_gui_basics.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_ActiveXComponent_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_ActiveXComponent_windows.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_AndroidViewComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_AndroidViewComponent.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_HWNDComponent_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_HWNDComponent_windows.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_android.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_android.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_ios.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_ios.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_mac.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_mac.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_linux.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_linux.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_mac.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_mac.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_windows.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_android.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_android.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_linux.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_linux.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_windows.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_XEmbedComponent_linux.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_XEmbedComponent_linux.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\juce_gui_extra.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\juce_gui_extra.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\BinaryData.cpp"/>
@ -2956,6 +2970,9 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Source\DemoUtilities.h"/>
<ClInclude Include="..\..\Source\PluginEditor.h"/>
<ClInclude Include="..\..\Source\PluginProcessor.h"/>
<ClInclude Include="..\..\Source\CircularBuffer.h"/>
<ClInclude Include="..\..\Source\shifter_voice.h"/>
<ClInclude Include="..\..\Source\adsr.h"/>
<ClInclude Include="..\..\Source\port.h"/>
@ -4282,36 +4299,36 @@
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_basics\windows\juce_VBlankAttachment.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_basics\windows\juce_WindowUtils.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_basics\juce_gui_basics.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniserFunctions.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\detail\juce_WebControlRelayEvents.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_ActiveXControlComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_AndroidViewComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_HWNDComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_NSViewComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_UIViewComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_XEmbedComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_AppleRemote.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebControlParameterIndexReceiver.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_NSViewFrameWatcher_mac.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniserFunctions.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\detail\juce_WebControlRelayEvents.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_ActiveXControlComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_AndroidViewComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_HWNDComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_NSViewComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_UIViewComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_XEmbedComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_AppleRemote.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebControlParameterIndexReceiver.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_NSViewFrameWatcher_mac.h"/>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\juce_gui_extra.h"/>
<ClInclude Include="..\..\JuceLibraryCode\BinaryData.h"/>
<ClInclude Include="..\..\JuceLibraryCode\JuceHeader.h"/>

View File

@ -685,6 +685,12 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\Source\PluginEditor.cpp">
<Filter>Harmonizer\Source</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\PluginProcessor.cpp">
<Filter>Harmonizer\Source</Filter>
</ClCompile>
<ClCompile Include="..\..\Source\shifter_voice.cpp">
<Filter>Harmonizer\Source</Filter>
</ClCompile>
@ -3517,115 +3523,115 @@
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_basics\juce_gui_basics.mm">
<Filter>JUCE Modules\juce_gui_basics</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.cpp">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.cpp">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.cpp">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.cpp">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.cpp">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.cpp">
<Filter>JUCE Modules\juce_gui_extra\documents</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.cpp">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_ActiveXComponent_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_ActiveXComponent_windows.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_AndroidViewComponent.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_AndroidViewComponent.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_AppleRemote_mac.mm">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_AppleRemote_mac.mm">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_HWNDComponent_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_HWNDComponent_windows.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_NSViewComponent_mac.mm">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_NSViewComponent_mac.mm">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_android.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_android.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_ios.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_ios.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_mac.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_PushNotifications_mac.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_linux.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_linux.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_mac.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_mac.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_SystemTrayIcon_windows.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_UIViewComponent_ios.mm">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_UIViewComponent_ios.mm">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_android.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_android.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_linux.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_linux.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_mac.mm">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_mac.mm">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_windows.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_WebBrowserComponent_windows.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_XEmbedComponent_linux.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_XEmbedComponent_linux.cpp">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\juce_gui_extra.cpp">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\juce_gui_extra.cpp">
<Filter>JUCE Modules\juce_gui_extra</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\juce_gui_extra.mm">
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\juce_gui_extra.mm">
<Filter>JUCE Modules\juce_gui_extra</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\BinaryData.cpp">
@ -3690,6 +3696,15 @@
<ClInclude Include="..\..\Source\DemoUtilities.h">
<Filter>Harmonizer\Assets</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\PluginEditor.h">
<Filter>Harmonizer\Source</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\PluginProcessor.h">
<Filter>Harmonizer\Source</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\CircularBuffer.h">
<Filter>Harmonizer\Source</Filter>
</ClInclude>
<ClInclude Include="..\..\Source\shifter_voice.h">
<Filter>Harmonizer\Source</Filter>
</ClInclude>
@ -7668,94 +7683,94 @@
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_basics\juce_gui_basics.h">
<Filter>JUCE Modules\juce_gui_basics</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeDocument.h">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeEditorComponent.h">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CodeTokeniser.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CodeTokeniser.h">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniser.h">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniserFunctions.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_CPlusPlusCodeTokeniserFunctions.h">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_LuaCodeTokeniser.h">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\code_editor\juce_XMLCodeTokeniser.h">
<Filter>JUCE Modules\juce_gui_extra\code_editor</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\detail\juce_WebControlRelayEvents.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\detail\juce_WebControlRelayEvents.h">
<Filter>JUCE Modules\juce_gui_extra\detail</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\documents\juce_FileBasedDocument.h">
<Filter>JUCE Modules\juce_gui_extra\documents</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_ActiveXControlComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_ActiveXControlComponent.h">
<Filter>JUCE Modules\juce_gui_extra\embedding</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_AndroidViewComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_AndroidViewComponent.h">
<Filter>JUCE Modules\juce_gui_extra\embedding</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_HWNDComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_HWNDComponent.h">
<Filter>JUCE Modules\juce_gui_extra\embedding</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_NSViewComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_NSViewComponent.h">
<Filter>JUCE Modules\juce_gui_extra\embedding</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_UIViewComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_UIViewComponent.h">
<Filter>JUCE Modules\juce_gui_extra\embedding</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\embedding\juce_XEmbedComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\embedding\juce_XEmbedComponent.h">
<Filter>JUCE Modules\juce_gui_extra\embedding</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_AnimatedAppComponent.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_AppleRemote.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_AppleRemote.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_BubbleMessageComponent.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_ColourSelector.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_KeyMappingEditorComponent.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_LiveConstantEditor.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PreferencesPanel.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_PushNotifications.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_RecentlyOpenedFilesList.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SplashScreen.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_SystemTrayIconComponent.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebBrowserComponent.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebControlParameterIndexReceiver.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebControlParameterIndexReceiver.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\misc\juce_WebControlRelays.h">
<Filter>JUCE Modules\juce_gui_extra\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\juce-8.0.4-windows\JUCE\modules\juce_gui_extra\native\juce_NSViewFrameWatcher_mac.h">
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\native\juce_NSViewFrameWatcher_mac.h">
<Filter>JUCE Modules\juce_gui_extra\native</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\..\Downloads\JUCE\modules\juce_gui_extra\juce_gui_extra.h">

View File

@ -69,7 +69,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -83,7 +83,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -103,6 +103,10 @@
<Lib>
<AdditionalDependencies>Harmonizer.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<PostBuildEvent>
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Debug\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
@ -115,7 +119,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -129,7 +133,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=1;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -152,6 +156,14 @@
<Lib>
<AdditionalDependencies>Harmonizer.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<PreBuildEvent>
<Command>cmd /c &quot;(cd /d ..\..\Assets\web &amp;&amp; npm run build &amp;&amp; npm run zip)&quot;
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Release\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_audio_plugin_client\juce_audio_plugin_client_Standalone.cpp">

View File

@ -69,7 +69,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -83,7 +83,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -122,7 +122,8 @@ if not exist &quot;$(OutDir)\\Harmonizer.vst3\Contents\x86_64-win\&quot; (
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>copy /Y &quot;$(OutDir)\Harmonizer.dll&quot; &quot;$(OutDir)\Harmonizer.vst3\Contents\x86_64-win\Harmonizer.vst3&quot;
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Debug\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
copy /Y &quot;$(OutDir)\Harmonizer.dll&quot; &quot;$(OutDir)\Harmonizer.vst3\Contents\x86_64-win\Harmonizer.vst3&quot;
set manifest_generated=0
if &quot;$(PROCESSOR_ARCHITECTURE)&quot; == &quot;ARM64&quot; if &quot;$(Platform)&quot; == &quot;x64&quot; (
call :_generate_manifest
@ -168,7 +169,7 @@ echo : Info: VST3 manifest generation is disabled for Harmonizer because a AMD64
<ClCompile>
<Optimization>Full</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -182,7 +183,7 @@ echo : Info: VST3 manifest generation is disabled for Harmonizer because a AMD64
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=1;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -206,7 +207,8 @@ echo : Info: VST3 manifest generation is disabled for Harmonizer because a AMD64
<AdditionalDependencies>Harmonizer.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
<PreBuildEvent>
<Command>if &quot;$(PROCESSOR_ARCHITECTURE)&quot; == &quot;x86&quot; if defined PROCESSOR_ARCHITEW6432 (
<Command>cmd /c &quot;(cd /d ..\..\Assets\web &amp;&amp; npm run build &amp;&amp; npm run zip)&quot;
if &quot;$(PROCESSOR_ARCHITECTURE)&quot; == &quot;x86&quot; if defined PROCESSOR_ARCHITEW6432 (
echo : Warning: Toolchain configuration issue! You are using a 32-bit toolchain to compile a 64-bit target on a 64-bit system. This may cause problems with the build system. To resolve this, use the x64 version of MSBuild. You can invoke it directly at: &quot;&lt;VisualStudioPathHere&gt;/MSBuild/Current/Bin/amd64/MSBuild.exe&quot; Or, use the &quot;x64 Native Tools Command Prompt&quot; script.
)
if not exist &quot;$(OutDir)\\Harmonizer.vst3\&quot; (
@ -224,7 +226,8 @@ if not exist &quot;$(OutDir)\\Harmonizer.vst3\Contents\x86_64-win\&quot; (
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>copy /Y &quot;$(OutDir)\Harmonizer.dll&quot; &quot;$(OutDir)\Harmonizer.vst3\Contents\x86_64-win\Harmonizer.vst3&quot;
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Release\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
copy /Y &quot;$(OutDir)\Harmonizer.dll&quot; &quot;$(OutDir)\Harmonizer.vst3\Contents\x86_64-win\Harmonizer.vst3&quot;
set manifest_generated=0
if &quot;$(PROCESSOR_ARCHITECTURE)&quot; == &quot;ARM64&quot; if &quot;$(Platform)&quot; == &quot;x64&quot; (
call :_generate_manifest

View File

@ -67,7 +67,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -81,7 +81,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -100,6 +100,10 @@
<Manifest>
<AdditionalManifestFiles/>
</Manifest>
<PostBuildEvent>
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Debug\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
@ -112,7 +116,7 @@
<ClCompile>
<Optimization>Full</Optimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=&quot;Harmonizer&quot;;JucePlugin_Desc=&quot;Harmonizer&quot;;JucePlugin_Manufacturer=&quot;yourcompany&quot;;JucePlugin_ManufacturerWebsite=&quot;www.yourcompany.com&quot;;JucePlugin_ManufacturerEmail=&quot;&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=&quot;1.0.0&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=&quot;Fx&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=&quot;HarmonizerAU&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=&quot;yourcompany: Harmonizer&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=&quot;com.yourcompany.Harmonizer.factory&quot;;JucePlugin_ARADocumentArchiveID=&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0&quot;;JucePlugin_ARACompatibleArchiveIDs=&quot;&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
@ -126,7 +130,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<ResourceCompile>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\juce-8.0.4-windows\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\..\..\..\..\Downloads\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\..\..\..\Downloads\JUCE\modules;C:\Users\mickl\Downloads\JUCE\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;JUCE_PROJUCER_VERSION=0x8000a;JUCE_MODULE_AVAILABLE_juce_audio_basics=1;JUCE_MODULE_AVAILABLE_juce_audio_devices=1;JUCE_MODULE_AVAILABLE_juce_audio_formats=1;JUCE_MODULE_AVAILABLE_juce_audio_plugin_client=1;JUCE_MODULE_AVAILABLE_juce_audio_processors=1;JUCE_MODULE_AVAILABLE_juce_audio_utils=1;JUCE_MODULE_AVAILABLE_juce_core=1;JUCE_MODULE_AVAILABLE_juce_data_structures=1;JUCE_MODULE_AVAILABLE_juce_dsp=1;JUCE_MODULE_AVAILABLE_juce_events=1;JUCE_MODULE_AVAILABLE_juce_graphics=1;JUCE_MODULE_AVAILABLE_juce_gui_basics=1;JUCE_MODULE_AVAILABLE_juce_gui_extra=1;JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1;JUCE_VST3_CAN_REPLACE_VST2=0;JUCE_STRICT_REFCOUNTEDPOINTER=1;JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;JucePlugin_Enable_IAA=0;JucePlugin_Enable_ARA=0;JucePlugin_Name=\&quot;Harmonizer\&quot;;JucePlugin_Desc=\&quot;Harmonizer\&quot;;JucePlugin_Manufacturer=\&quot;yourcompany\&quot;;JucePlugin_ManufacturerWebsite=\&quot;www.yourcompany.com\&quot;;JucePlugin_ManufacturerEmail=\&quot;\&quot;;JucePlugin_ManufacturerCode=0x4d616e75;JucePlugin_PluginCode=0x456d6377;JucePlugin_IsSynth=0;JucePlugin_WantsMidiInput=1;JucePlugin_ProducesMidiOutput=0;JucePlugin_IsMidiEffect=0;JucePlugin_EditorRequiresKeyboardFocus=0;JucePlugin_Version=1.0.0;JucePlugin_VersionCode=0x10000;JucePlugin_VersionString=\&quot;1.0.0\&quot;;JucePlugin_VSTUniqueID=JucePlugin_PluginCode;JucePlugin_VSTCategory=kPlugCategEffect;JucePlugin_Vst3Category=\&quot;Fx\&quot;;JucePlugin_AUMainType='aufx';JucePlugin_AUSubType=JucePlugin_PluginCode;JucePlugin_AUExportPrefix=HarmonizerAU;JucePlugin_AUExportPrefixQuoted=\&quot;HarmonizerAU\&quot;;JucePlugin_AUManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_CFBundleIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXIdentifier=com.yourcompany.Harmonizer;JucePlugin_AAXManufacturerCode=JucePlugin_ManufacturerCode;JucePlugin_AAXProductId=JucePlugin_PluginCode;JucePlugin_AAXCategory=0;JucePlugin_AAXDisableBypass=0;JucePlugin_AAXDisableMultiMono=0;JucePlugin_IAAType=0x6175726d;JucePlugin_IAASubType=JucePlugin_PluginCode;JucePlugin_IAAName=\&quot;yourcompany: Harmonizer\&quot;;JucePlugin_VSTNumMidiInputs=16;JucePlugin_VSTNumMidiOutputs=16;JucePlugin_ARAContentTypes=0;JucePlugin_ARATransformationFlags=0;JucePlugin_ARAFactoryID=\&quot;com.yourcompany.Harmonizer.factory\&quot;;JucePlugin_ARADocumentArchiveID=\&quot;com.yourcompany.Harmonizer.aradocumentarchive.1.0.0\&quot;;JucePlugin_ARACompatibleArchiveIDs=\&quot;\&quot;;JUCE_STANDALONE_APPLICATION=JucePlugin_Build_Standalone;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcVXNlcnNcbWlja2xcRG93bmxvYWRzXGp1Y2UtOC4wLjQtd2luZG93c1xKVUNFXGV4YW1wbGVz;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=1.0.0;JUCE_APP_VERSION_HEX=0x10000;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
@ -148,6 +152,14 @@
<Manifest>
<AdditionalManifestFiles/>
</Manifest>
<PreBuildEvent>
<Command>cmd /c &quot;(cd /d ..\..\Assets\web &amp;&amp; npm run build &amp;&amp; npm run zip)&quot;
</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>xcopy &quot;..\..\Builds\VisualStudio2022\x64\Release\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I
</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\..\Downloads\JUCE\modules\juce_audio_plugin_client\VST3\juce_VST3ManifestHelper.cpp"/>

View File

@ -0,0 +1,714 @@
#pragma once
/*
==============================================================================
This file is part of the JUCE framework examples.
Copyright (c) Raw Material Software Limited
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
to use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
==============================================================================
*/
/*******************************************************************************
The block below describes the properties of this PIP. A PIP is a short snippet
of code that can be read by the Projucer and used to generate a JUCE project.
BEGIN_JUCE_PIP_METADATA
name: WebViewPluginDemo
version: 1.0.0
vendor: JUCE
website: http://juce.com
description: Filtering audio plugin using an HTML/JS user interface
dependencies: juce_audio_basics, juce_audio_devices, juce_audio_formats,
juce_audio_plugin_client, juce_audio_processors, juce_dsp,
juce_audio_utils, juce_core, juce_data_structures,
juce_events, juce_graphics, juce_gui_basics, juce_gui_extra
exporters: xcode_mac, vs2022, linux_make, androidstudio, xcode_iphone
moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1, JUCE_USE_WIN_WEBVIEW2_WITH_STATIC_LINKING=1
type: AudioProcessor
mainClass: WebViewPluginAudioProcessorWrapper
useLocalCopy: 1
END_JUCE_PIP_METADATA
*******************************************************************************/
#pragma once
#include "DemoUtilities.h"
#include <JuceHeader.h>
#include "Shifter.h"
//using namespace juce::dsp;
namespace ID
{
#define PARAMETER_ID(str) static const ParameterID str { #str, 1 };
PARAMETER_ID(formantPreserve)
PARAMETER_ID(autoTuneSpeed)
PARAMETER_ID(autoTuneDepth)
PARAMETER_ID(portTime)
PARAMETER_ID(mute)
PARAMETER_ID(filterType)
#undef PARAMETER_ID
}
class CircularBuffer
{
public:
CircularBuffer(int numChannels, int numSamples)
: buffer(data, (size_t)numChannels, (size_t)numSamples)
{
}
template <typename T>
void push(dsp::AudioBlock<T> b)
{
jassert(b.getNumChannels() == buffer.getNumChannels());
const auto trimmed = b.getSubBlock(b.getNumSamples()
- std::min(b.getNumSamples(), buffer.getNumSamples()));
const auto bufferLength = (int64)buffer.getNumSamples();
for (auto samplesRemaining = (int64)trimmed.getNumSamples(); samplesRemaining > 0;)
{
const auto writeOffset = writeIx % bufferLength;
const auto numSamplesToWrite = std::min(samplesRemaining, bufferLength - writeOffset);
auto destSubBlock = buffer.getSubBlock((size_t)writeOffset, (size_t)numSamplesToWrite);
const auto sourceSubBlock = trimmed.getSubBlock(trimmed.getNumSamples() - (size_t)samplesRemaining,
(size_t)numSamplesToWrite);
destSubBlock.copyFrom(sourceSubBlock);
samplesRemaining -= numSamplesToWrite;
writeIx += numSamplesToWrite;
}
}
template <typename T>
void push(Span<T> s)
{
auto* ptr = s.begin();
dsp::AudioBlock<T> b(&ptr, 1, s.size());
push(b);
}
void read(int64 readIx, dsp::AudioBlock<float> output) const
{
const auto numChannelsToUse = std::min(buffer.getNumChannels(), output.getNumChannels());
jassert(output.getNumChannels() == buffer.getNumChannels());
const auto bufferLength = (int64)buffer.getNumSamples();
for (auto outputOffset = (size_t)0; outputOffset < output.getNumSamples();)
{
const auto inputOffset = (size_t)((readIx + (int64)outputOffset) % bufferLength);
const auto numSamplesToRead = std::min(output.getNumSamples() - outputOffset,
(size_t)bufferLength - inputOffset);
auto destSubBlock = output.getSubBlock(outputOffset, numSamplesToRead)
.getSubsetChannelBlock(0, numChannelsToUse);
destSubBlock.copyFrom(buffer.getSubBlock(inputOffset, numSamplesToRead)
.getSubsetChannelBlock(0, numChannelsToUse));
outputOffset += numSamplesToRead;
}
}
int64 getWriteIndex() const noexcept { return writeIx; }
private:
HeapBlock<char> data;
dsp::AudioBlock<float> buffer;
int64 writeIx = 0;
};
//class SpectralBars
//{
//public:
// //template <typename T>
// void push(int data)
// {
// testQueue.push(data);
// }
//
// void compute(Span<int> output) {
// int index = 0;
// for (auto it = output.begin(); it != output.end(); ++it) {
// *it = testQueue.get(index++);
// }
// }
//
//
//private:
// circ_queue<int, 256> testQueue;
//};
//==============================================================================
class WebViewPluginAudioProcessor : public AudioProcessor
{
public:
//==============================================================================
WebViewPluginAudioProcessor(AudioProcessorValueTreeState::ParameterLayout layout);
//==============================================================================
void prepareToPlay(double sampleRate, int samplesPerBlock) override;
void releaseResources() override {}
bool isBusesLayoutSupported(const BusesLayout& layouts) const override;
void processBlock(AudioBuffer<float>&, MidiBuffer&) override;
using AudioProcessor::processBlock;
//==============================================================================
const String getName() const override { return JucePlugin_Name; }
bool acceptsMidi() const override { return false; }
bool producesMidi() const override { return false; }
bool isMidiEffect() const override { return false; }
double getTailLengthSeconds() const override { return 0.0; }
//==============================================================================
int getNumPrograms() override { return 1; }
int getCurrentProgram() override { return 0; }
void setCurrentProgram(int) override {}
const String getProgramName(int) override { return {}; }
void changeProgramName(int, const String&) override {}
//==============================================================================
void getStateInformation(MemoryBlock& destData) override;
void setStateInformation(const void* data, int sizeInBytes) override;
bool new_midi = false;
struct Parameters
{
public:
explicit Parameters(AudioProcessorValueTreeState::ParameterLayout& layout)
: formantPreserve(addToLayout<AudioParameterFloat>(layout,
ID::formantPreserve,
"Formant Preserve",
NormalisableRange<float> {0.0f, 1.0f, .01f},
.5f)),
autoTuneSpeed(addToLayout<AudioParameterFloat>(layout,
ID::autoTuneSpeed,
"AutoTune Speed",
NormalisableRange<float> {0.001f, 0.1f, .001f},
.5f)),
autoTuneDepth(addToLayout<AudioParameterFloat>(layout,
ID::autoTuneDepth,
"AutoTune Depth",
NormalisableRange<float> {0.0f, 1.1f, .01f},
.5f)),
portTime(addToLayout<AudioParameterFloat>(layout,
ID::portTime,
"Portamento Speed",
NormalisableRange<float> {0.001f, 0.2f, .001f},
.01f)),
mute(addToLayout<AudioParameterBool>(layout, ID::mute, "Mute", false)),
filterType(addToLayout<AudioParameterChoice>(layout,
ID::filterType,
"Filter type",
StringArray{ "Low-pass", "High-pass", "Band-pass" },
0))
{
}
AudioParameterFloat& formantPreserve;
AudioParameterFloat& autoTuneSpeed;
AudioParameterFloat& autoTuneDepth;
AudioParameterFloat& portTime;
AudioParameterBool& mute;
AudioParameterChoice& filterType;
private:
template <typename Param>
static void add(AudioProcessorParameterGroup& group, std::unique_ptr<Param> param)
{
group.addChild(std::move(param));
}
template <typename Param>
static void add(AudioProcessorValueTreeState::ParameterLayout& group, std::unique_ptr<Param> param)
{
group.add(std::move(param));
}
template <typename Param, typename Group, typename... Ts>
static Param& addToLayout(Group& layout, Ts&&... ts)
{
auto param = std::make_unique<Param>(std::forward<Ts>(ts)...);
auto& ref = *param;
add(layout, std::move(param));
return ref;
}
};
Parameters parameters;
AudioProcessorValueTreeState state;
SpinLock midiLock;
/*std::vector<int> spectrumData = [] { return std::vector<int>(256, 0.0f); }();
SpinLock spectrumDataLock;
SpectralBars spectralBars;*/
dsp::LadderFilter<float> filter;
Shifter shifter;
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessor)
};
//==============================================================================
WebViewPluginAudioProcessor::WebViewPluginAudioProcessor(AudioProcessorValueTreeState::ParameterLayout layout)
: AudioProcessor(BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput("Input", juce::AudioChannelSet::stereo(), true)
#endif
.withOutput("Output", juce::AudioChannelSet::stereo(), true)
#endif
),
parameters(layout),
state(*this, nullptr, "STATE", std::move(layout))
{
shifter.Init(48000.0f, 48);
}
//==============================================================================
void WebViewPluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
const auto channels = std::max(getTotalNumInputChannels(), getTotalNumOutputChannels());
shifter.Init((float)sampleRate, samplesPerBlock);
if (channels == 0)
return;
filter.prepare({ sampleRate, (uint32_t)samplesPerBlock, (uint32_t)channels });
filter.reset();
}
bool WebViewPluginAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const
{
if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
return false;
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
return true;
}
void WebViewPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer,
juce::MidiBuffer& midi)
{
juce::ScopedNoDenormals noDenormals;
const auto totalNumInputChannels = getTotalNumInputChannels();
const auto totalNumOutputChannels = getTotalNumOutputChannels();
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear(i, 0, buffer.getNumSamples());
shifter.SetFormantPreserve(parameters.formantPreserve.get());
shifter.SetAutoTuneSpeed(parameters.autoTuneSpeed.get());
shifter.SetAutoTuneDepth(parameters.autoTuneDepth.get());
shifter.SetPortamentoTime(parameters.portTime.get());
juce::AudioBuffer<float> const_buff;
const_buff.makeCopyOf(buffer);
shifter.Process(const_buff.getArrayOfReadPointers(), (float**)buffer.getArrayOfWritePointers(), buffer.getNumSamples());
for (const auto metadata : midi)
{
const auto msg = metadata.getMessage();
if (msg.isNoteOn()) {
shifter.AddMidiNote(msg.getNoteNumber());
new_midi = true;
//editor.webComponent.emitEventIfBrowserIsVisible("midNoteData", var{});
}
else if (msg.isNoteOff()) {
shifter.RemoveMidiNote(msg.getNoteNumber());
new_midi = true;
//editor.webComponent.emitEventIfBrowserIsVisible("midNoteData", var{});
}
}
{
//DBG(shifter.out_midi[MAX_VOICES]);
//push midi note
//spectralBars.push(shifter.out_midi[MAX_VOICES]);
const SpinLock::ScopedTryLockType lock(midiLock);
if (!lock.isLocked())
return;
}
/*for(auto i = 0; i < buffer.getNumSamples(); ++i)
{
bool process = (i % 256) == 0 && i != 0;
for(auto j = 0; j < totalNumInputChannels; ++j)
{
input[j][i] = buffer.getReadPointer(j)[i];
}
}
filter.setCutoffFrequencyHz (parameters.cutoffFreqHz.get());
const auto filterMode = [this]
{
switch (parameters.filterType.getIndex())
{
case 0:
return dsp::LadderFilter<float>::Mode::LPF12;
case 1:
return dsp::LadderFilter<float>::Mode::HPF12;
default:
return dsp::LadderFilter<float>::Mode::BPF12;
}
}();
filter.setMode (filterMode);
auto outBlock = dsp::AudioBlock<float> { buffer }.getSubsetChannelBlock (0, (size_t) getTotalNumOutputChannels());
if (parameters.mute.get())
outBlock.clear();
filter.process (dsp::ProcessContextReplacing<float> (outBlock));
spectralBars.push (Span { buffer.getReadPointer (0), (size_t) buffer.getNumSamples() });
{
const SpinLock::ScopedTryLockType lock (spectrumDataLock);
if (! lock.isLocked())
return;
spectralBars.compute ({ spectrumData.data(), spectrumData.size() });
}*/
}
//==============================================================================
void WebViewPluginAudioProcessor::getStateInformation(juce::MemoryBlock& destData)
{
juce::ignoreUnused(destData);
}
void WebViewPluginAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
{
juce::ignoreUnused(data, sizeInBytes);
}
extern const String localDevServerAddress;
std::optional<WebBrowserComponent::Resource> getResource(const String& url);
//==============================================================================
struct SinglePageBrowser : WebBrowserComponent
{
using WebBrowserComponent::WebBrowserComponent;
// Prevent page loads from navigating away from our single page web app
bool pageAboutToLoad(const String& newURL) override;
};
//==============================================================================
class WebViewPluginAudioProcessorEditor : public AudioProcessorEditor, private Timer
{
public:
explicit WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor&);
std::optional<WebBrowserComponent::Resource> getResource(const String& url);
//==============================================================================
void paint(Graphics&) override;
void resized() override;
int getControlParameterIndex(Component&) override
{
return controlParameterIndexReceiver.getControlParameterIndex();
}
void timerCallback() override
{
static constexpr size_t numFramesBuffered = 5;
SpinLock::ScopedLockType lock{ processorRef.midiLock };
static int64 callbackCounter = 0;
processorRef.new_midi = false;
juce::Array<var> notes;
int voice_num = 0;
for (auto& voice : processorRef.shifter.voices) {
if (voice.onoff_) {
auto obj = new DynamicObject();
obj->setProperty("voice", voice_num);
obj->setProperty("midi", voice.GetMidiNote());
notes.add(var(obj));
}
voice_num++;
}
DynamicObject::Ptr d(new DynamicObject());
d->setProperty("notes", notes);
d->setProperty("input_pitch", processorRef.shifter.getInputPitch());
d->setProperty("output_pitch", processorRef.shifter.getOutputPitch());
webComponent.emitEventIfBrowserIsVisible("midNoteData", d.get());
}
private:
WebViewPluginAudioProcessor& processorRef;
WebSliderRelay formantSliderRelay{ "formantSlider" };
WebSliderRelay autoTuneSpeedSliderRelay{ "autoTuneSpeedSlider" };
WebSliderRelay autoTuneDepthSliderRelay{ "autoTuneDepthSlider" };
WebSliderRelay portTimeSliderRelay{ "portTimeSlider" };
WebToggleButtonRelay muteToggleRelay{ "muteToggle" };
WebComboBoxRelay filterTypeComboRelay{ "filterTypeCombo" };
WebControlParameterIndexReceiver controlParameterIndexReceiver;
SinglePageBrowser webComponent{ WebBrowserComponent::Options{}
.withBackend(WebBrowserComponent::Options::Backend::webview2)
.withWinWebView2Options(WebBrowserComponent::Options::WinWebView2{}
.withUserDataFolder(File::getSpecialLocation(File::SpecialLocationType::tempDirectory)))
.withNativeIntegrationEnabled()
.withOptionsFrom(formantSliderRelay)
.withOptionsFrom(autoTuneSpeedSliderRelay)
.withOptionsFrom(autoTuneDepthSliderRelay)
.withOptionsFrom(portTimeSliderRelay)
.withOptionsFrom(muteToggleRelay)
.withOptionsFrom(filterTypeComboRelay)
.withOptionsFrom(controlParameterIndexReceiver)
.withNativeFunction("sayHello", [](auto& var, auto complete)
{
complete("Hello " + var[0].toString());
})
.withResourceProvider([this](const auto& url)
{
return getResource(url);
},
URL { localDevServerAddress }.getOrigin()) };
WebSliderParameterAttachment formantAttachment;
WebSliderParameterAttachment autoTuneSpeedAttachment;
WebSliderParameterAttachment autoTuneDepthAttachment;
WebSliderParameterAttachment portTimeAttachment;
WebToggleButtonParameterAttachment muteAttachment;
WebComboBoxParameterAttachment filterTypeAttachment;
std::deque<Array<var>> spectrumDataFrames;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessorEditor)
};
static ZipFile* getZipFile()
{
static auto stream = createAssetInputStream("webviewplugin-gui_1.0.0.zip", AssertAssetExists::no);
if (stream == nullptr)
return nullptr;
static ZipFile f{ stream.get(), false };
return &f;
}
static const char* getMimeForExtension(const String& extension)
{
static const std::unordered_map<String, const char*> mimeMap =
{
{ { "htm" }, "text/html" },
{ { "html" }, "text/html" },
{ { "txt" }, "text/plain" },
{ { "jpg" }, "image/jpeg" },
{ { "jpeg" }, "image/jpeg" },
{ { "svg" }, "image/svg+xml" },
{ { "ico" }, "image/vnd.microsoft.icon" },
{ { "json" }, "application/json" },
{ { "png" }, "image/png" },
{ { "css" }, "text/css" },
{ { "map" }, "application/json" },
{ { "js" }, "text/javascript" },
{ { "woff2" }, "font/woff2" }
};
if (const auto it = mimeMap.find(extension.toLowerCase()); it != mimeMap.end())
return it->second;
jassertfalse;
return "";
}
static String getExtension(String filename)
{
return filename.fromLastOccurrenceOf(".", false, false);
}
static auto streamToVector(InputStream& stream)
{
std::vector<std::byte> result((size_t)stream.getTotalLength());
stream.setPosition(0);
[[maybe_unused]] const auto bytesRead = stream.read(result.data(), result.size());
jassert(bytesRead == (ssize_t)result.size());
return result;
}
std::optional<WebBrowserComponent::Resource> WebViewPluginAudioProcessorEditor::getResource(const String& url)
{
const auto urlToRetrive = url == "/" ? String{ "index.html" }
: url.fromFirstOccurrenceOf("/", false, false);
if (auto* archive = getZipFile())
{
if (auto* entry = archive->getEntry(urlToRetrive))
{
auto stream = rawToUniquePtr(archive->createStreamForEntry(*entry));
auto v = streamToVector(*stream);
auto mime = getMimeForExtension(getExtension(entry->filename).toLowerCase());
return WebBrowserComponent::Resource{ std::move(v),
std::move(mime) };
}
}
if (urlToRetrive == "index.html")
{
auto fallbackIndexHtml = createAssetInputStream("webviewplugin-gui-fallback.html");
return WebBrowserComponent::Resource{ streamToVector(*fallbackIndexHtml),
String { "text/html" } };
}
if (urlToRetrive == "data.txt")
{
WebBrowserComponent::Resource resource;
static constexpr char testData[] = "testdata";
MemoryInputStream stream{ testData, numElementsInArray(testData) - 1, false };
return WebBrowserComponent::Resource{ streamToVector(stream), String { "text/html" } };
}
if (urlToRetrive == "midNoteData.json")
{
juce::Array<var> notes;
int voice_num = 0;
for (auto& voice : processorRef.shifter.voices) {
if (voice.onoff_) {
auto obj = new DynamicObject();
obj->setProperty("voice", voice_num);
obj->setProperty("midi", voice.GetMidiNote());
notes.add(var(obj));
}
voice_num++;
}
DynamicObject::Ptr d(new DynamicObject());
d->setProperty("notes", notes);
const auto s = JSON::toString(d.get());
MemoryInputStream stream{ s.getCharPointer(), s.getNumBytesAsUTF8(), false };
return WebBrowserComponent::Resource{ streamToVector(stream), String { "application/json" } };
}
return std::nullopt;
}
#if JUCE_ANDROID
// The localhost is available on this address to the emulator
const String localDevServerAddress = "http://10.0.2.2:3000/";
#else
const String localDevServerAddress = "http://localhost:3000/";
#endif
bool SinglePageBrowser::pageAboutToLoad(const String& newURL)
{
return newURL == localDevServerAddress || newURL == getResourceProviderRoot();
}
//==============================================================================
WebViewPluginAudioProcessorEditor::WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor& p)
: AudioProcessorEditor(&p), processorRef(p),
formantAttachment(*processorRef.state.getParameter(ID::formantPreserve.getParamID()),
formantSliderRelay,
processorRef.state.undoManager),
autoTuneSpeedAttachment(*processorRef.state.getParameter(ID::autoTuneSpeed.getParamID()),
autoTuneSpeedSliderRelay,
processorRef.state.undoManager),
autoTuneDepthAttachment(*processorRef.state.getParameter(ID::autoTuneDepth.getParamID()),
autoTuneDepthSliderRelay,
processorRef.state.undoManager),
portTimeAttachment(*processorRef.state.getParameter(ID::portTime.getParamID()),
portTimeSliderRelay,
processorRef.state.undoManager),
muteAttachment(*processorRef.state.getParameter(ID::mute.getParamID()),
muteToggleRelay,
processorRef.state.undoManager),
filterTypeAttachment(*processorRef.state.getParameter(ID::filterType.getParamID()),
filterTypeComboRelay,
processorRef.state.undoManager)
{
addAndMakeVisible(webComponent);
webComponent.goToURL(localDevServerAddress);
//webComponent.goToURL (WebBrowserComponent::getResourceProviderRoot());
setSize(500, 500);
startTimerHz(60);
}
//==============================================================================
void WebViewPluginAudioProcessorEditor::paint(Graphics& g)
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
}
void WebViewPluginAudioProcessorEditor::resized()
{
webComponent.setBounds(getLocalBounds());
}
class WebViewPluginAudioProcessorWrapper : public WebViewPluginAudioProcessor
{
public:
WebViewPluginAudioProcessorWrapper() : WebViewPluginAudioProcessor({})
{
}
bool hasEditor() const override { return true; }
AudioProcessorEditor* createEditor() override {
return new WebViewPluginAudioProcessorEditor(*this);
}
};

View File

@ -10,6 +10,15 @@
resource="1" file="Assets/webviewplugin-gui-fallback.html"/>
</GROUP>
<GROUP id="{BA45FF6A-23B2-0FFB-BB29-84A581170899}" name="Source">
<FILE id="eO13ze" name="PluginEditor.cpp" compile="1" resource="0"
file="Source/PluginEditor.cpp"/>
<FILE id="izJGih" name="PluginEditor.h" compile="0" resource="0" file="Source/PluginEditor.h"/>
<FILE id="m8Uj9j" name="PluginProcessor.cpp" compile="1" resource="0"
file="Source/PluginProcessor.cpp"/>
<FILE id="UtuXpw" name="PluginProcessor.h" compile="0" resource="0"
file="Source/PluginProcessor.h"/>
<FILE id="N1TngJ" name="CircularBuffer.h" compile="0" resource="0"
file="Source/CircularBuffer.h"/>
<FILE id="dgTaja" name="shifter_voice.cpp" compile="1" resource="0"
file="Source/shifter_voice.cpp"/>
<FILE id="clLeAX" name="shifter_voice.h" compile="0" resource="0" file="Source/shifter_voice.h"/>
@ -49,8 +58,9 @@
<EXPORTFORMATS>
<VS2022 targetFolder="Builds/VisualStudio2022">
<CONFIGURATIONS>
<CONFIGURATION isDebug="1" name="Debug" targetName="Harmonizer"/>
<CONFIGURATION isDebug="0" name="Release" targetName="Harmonizer"/>
<CONFIGURATION isDebug="1" name="Debug" targetName="Harmonizer" postbuildCommand="xcopy &quot;..\..\Builds\VisualStudio2022\x64\Debug\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I"/>
<CONFIGURATION isDebug="0" name="Release" targetName="Harmonizer" prebuildCommand="cmd /c &quot;(cd /d ..\..\Assets\web &amp;&amp; npm run build &amp;&amp; npm run zip)&quot;"
postbuildCommand="xcopy &quot;..\..\Builds\VisualStudio2022\x64\Release\VST3\Harmonizer.vst3\&quot; &quot;C:\Users\mickl\Documents\VstPlugins\Harmonizer.vst3&quot; /Y /E /I&#10;&#10;"/>
</CONFIGURATIONS>
<MODULEPATHS>
<MODULEPATH id="juce_audio_basics" path="../../../Downloads/JUCE/modules"/>

86
Source/CircularBuffer.h Normal file
View File

@ -0,0 +1,86 @@
/*
==============================================================================
CircularBuffer.h
Created: 4 Nov 2025 6:20:15pm
Author: mickl
==============================================================================
*/
#pragma once
#include <JuceHeader.h>
class CircularBuffer
{
public:
CircularBuffer(int numChannels, int numSamples)
: buffer(data, (size_t)numChannels, (size_t)numSamples)
{
}
template <typename T>
void push(dsp::AudioBlock<T> b)
{
jassert(b.getNumChannels() == buffer.getNumChannels());
const auto trimmed = b.getSubBlock(b.getNumSamples()
- std::min(b.getNumSamples(), buffer.getNumSamples()));
const auto bufferLength = (int64)buffer.getNumSamples();
for (auto samplesRemaining = (int64)trimmed.getNumSamples(); samplesRemaining > 0;)
{
const auto writeOffset = writeIx % bufferLength;
const auto numSamplesToWrite = std::min(samplesRemaining, bufferLength - writeOffset);
auto destSubBlock = buffer.getSubBlock((size_t)writeOffset, (size_t)numSamplesToWrite);
const auto sourceSubBlock = trimmed.getSubBlock(trimmed.getNumSamples() - (size_t)samplesRemaining,
(size_t)numSamplesToWrite);
destSubBlock.copyFrom(sourceSubBlock);
samplesRemaining -= numSamplesToWrite;
writeIx += numSamplesToWrite;
}
}
template <typename T>
void push(Span<T> s)
{
auto* ptr = s.begin();
dsp::AudioBlock<T> b(&ptr, 1, s.size());
push(b);
}
void read(int64 readIx, dsp::AudioBlock<float> output) const
{
const auto numChannelsToUse = std::min(buffer.getNumChannels(), output.getNumChannels());
jassert(output.getNumChannels() == buffer.getNumChannels());
const auto bufferLength = (int64)buffer.getNumSamples();
for (auto outputOffset = (size_t)0; outputOffset < output.getNumSamples();)
{
const auto inputOffset = (size_t)((readIx + (int64)outputOffset) % bufferLength);
const auto numSamplesToRead = std::min(output.getNumSamples() - outputOffset,
(size_t)bufferLength - inputOffset);
auto destSubBlock = output.getSubBlock(outputOffset, numSamplesToRead)
.getSubsetChannelBlock(0, numChannelsToUse);
destSubBlock.copyFrom(buffer.getSubBlock(inputOffset, numSamplesToRead)
.getSubsetChannelBlock(0, numChannelsToUse));
outputOffset += numSamplesToRead;
}
}
int64 getWriteIndex() const noexcept { return writeIx; }
private:
HeapBlock<char> data;
dsp::AudioBlock<float> buffer;
int64 writeIx = 0;
};

View File

@ -45,11 +45,13 @@ void Helmholtz::iosamples(const t_float* in, t_float* out, int size)
int mask = framesize - 1;
int outindex = 0;
// call analysis function when it is time
if (!(timeindex & (framesize / overlap - 1))) analyzeframe();
while (size--)
{
// call analysis function when it is time
if (!(timeindex & (framesize / overlap - 1))) analyzeframe();
inputbuf[timeindex++] = *in++;
//out[outindex++] = processbuf[timeindex++];
timeindex &= mask;

View File

@ -50,8 +50,8 @@ against another DSP framework, you need to define t_float, and you need to
include Ron Mayer's fft or similar functionality. */
#include "mayer_fft.h"
#define REALFFT mayer_realfft
#define REALIFFT mayer_realifft
#define REALFFT fft.realfft
#define REALIFFT fft.realifft
/***********************************************************************/
@ -104,6 +104,7 @@ private:
t_float fidelity;
t_float biasfactor;
t_float minrms;
MayerFFT fft;
};
#endif // #ifndef Helmholtz_H

216
Source/PluginEditor.cpp Normal file
View File

@ -0,0 +1,216 @@
/*
==============================================================================
PluginEditor.cpp
Created: 4 Nov 2025 6:20:46pm
Author: mickl
==============================================================================
*/
#include "PluginEditor.h"
#include "DemoUtilities.h"
static ZipFile* getZipFile()
{
static auto stream = createAssetInputStream("webviewplugin-gui_1.0.0.zip", AssertAssetExists::no);
if (stream == nullptr)
return nullptr;
static ZipFile f{ stream.get(), false };
return &f;
}
static const char* getMimeForExtension(const String& extension)
{
static const std::unordered_map<String, const char*> mimeMap =
{
{ { "htm" }, "text/html" },
{ { "html" }, "text/html" },
{ { "txt" }, "text/plain" },
{ { "jpg" }, "image/jpeg" },
{ { "jpeg" }, "image/jpeg" },
{ { "svg" }, "image/svg+xml" },
{ { "ico" }, "image/vnd.microsoft.icon" },
{ { "json" }, "application/json" },
{ { "png" }, "image/png" },
{ { "css" }, "text/css" },
{ { "map" }, "application/json" },
{ { "js" }, "text/javascript" },
{ { "woff2" }, "font/woff2" }
};
if (const auto it = mimeMap.find(extension.toLowerCase()); it != mimeMap.end())
return it->second;
jassertfalse;
return "";
}
static String getExtension(String filename)
{
return filename.fromLastOccurrenceOf(".", false, false);
}
static auto streamToVector(InputStream& stream)
{
std::vector<std::byte> result((size_t)stream.getTotalLength());
stream.setPosition(0);
[[maybe_unused]] const auto bytesRead = stream.read(result.data(), result.size());
jassert(bytesRead == (ssize_t)result.size());
return result;
}
std::optional<WebBrowserComponent::Resource> WebViewPluginAudioProcessorEditor::getResource(const String& url)
{
const auto urlToRetrive = url == "/" ? String{ "index.html" }
: url.fromFirstOccurrenceOf("/", false, false);
if (auto* archive = getZipFile())
{
if (auto* entry = archive->getEntry(urlToRetrive))
{
auto stream = rawToUniquePtr(archive->createStreamForEntry(*entry));
auto v = streamToVector(*stream);
auto mime = getMimeForExtension(getExtension(entry->filename).toLowerCase());
return WebBrowserComponent::Resource{ std::move(v),
std::move(mime) };
}
}
if (urlToRetrive == "index.html")
{
auto fallbackIndexHtml = createAssetInputStream("webviewplugin-gui-fallback.html");
return WebBrowserComponent::Resource{ streamToVector(*fallbackIndexHtml),
String { "text/html" } };
}
if (urlToRetrive == "data.txt")
{
WebBrowserComponent::Resource resource;
static constexpr char testData[] = "testdata";
MemoryInputStream stream{ testData, numElementsInArray(testData) - 1, false };
return WebBrowserComponent::Resource{ streamToVector(stream), String { "text/html" } };
}
if (urlToRetrive == "midNoteData.json")
{
juce::Array<var> notes;
int voice_num = 0;
for (auto& voice : processorRef.shifter.voices) {
if (voice.onoff_) {
auto obj = new DynamicObject();
obj->setProperty("voice", voice_num);
obj->setProperty("midi", voice.GetMidiNote());
notes.add(var(obj));
}
voice_num++;
}
DynamicObject::Ptr d(new DynamicObject());
d->setProperty("notes", notes);
const auto s = JSON::toString(d.get());
MemoryInputStream stream{ s.getCharPointer(), s.getNumBytesAsUTF8(), false };
return WebBrowserComponent::Resource{ streamToVector(stream), String { "application/json" } };
}
return std::nullopt;
}
#if JUCE_ANDROID
// The localhost is available on this address to the emulator
const String localDevServerAddress = "http://10.0.2.2:3000/";
#else
const String localDevServerAddress = "http://localhost:3000/";
#endif
bool SinglePageBrowser::pageAboutToLoad(const String& newURL)
{
return newURL == localDevServerAddress || newURL == getResourceProviderRoot();
}
WebViewPluginAudioProcessorEditor::WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor& p)
: AudioProcessorEditor(&p), processorRef(p)
{
auto options = WebBrowserComponent::Options{}
.withBackend(WebBrowserComponent::Options::Backend::webview2)
.withWinWebView2Options(WebBrowserComponent::Options::WinWebView2{}
.withUserDataFolder(File::getSpecialLocation(File::SpecialLocationType::tempDirectory)))
.withNativeIntegrationEnabled()
.withOptionsFrom(controlParameterIndexReceiver)
.withResourceProvider([this](const auto& url)
{
return getResource(url);
},
URL{ localDevServerAddress }.getOrigin());
for (auto& sliderId : p.parameters.sliderIds) {
slider_relays.push_back(new WebSliderRelay{ sliderId });
slider_attatchments.push_back(new
WebSliderParameterAttachment(
*processorRef.state.getParameter(sliderId),
*slider_relays.back(),
processorRef.state.undoManager));
options = options.withOptionsFrom(*slider_relays.back());
}
for (auto& toggleId : p.parameters.toggleIds) {
toggle_relays.push_back(new WebToggleButtonRelay{ toggleId });
toggle_attatchments.push_back(new
WebToggleButtonParameterAttachment(
*processorRef.state.getParameter(toggleId),
*toggle_relays.back(),
processorRef.state.undoManager));
options = options.withOptionsFrom(*toggle_relays.back());
}
webComponent = new SinglePageBrowser(options);
addAndMakeVisible(*webComponent);
#if DEBUG
webComponent->goToURL(localDevServerAddress);
#else
webComponent->goToURL (WebBrowserComponent::getResourceProviderRoot());
#endif
setSize(800, 436);
startTimerHz(60);
/*for (int i = 0; i < processorRef.parameters.sliderIds.size(); ++i) {
slider_attatchments.push_back(new
WebSliderParameterAttachment(
*processorRef.state.getParameter(processorRef.parameters.sliderIds[i]),
*slider_relays.back(),
processorRef.state.undoManager));
}
for (int i = 0; i < processorRef.parameters.toggleIds.size(); ++i) {
toggle_attatchments.push_back(new
WebToggleButtonParameterAttachment(
*processorRef.state.getParameter(processorRef.parameters.toggleIds[i]),
*toggle_relays.back(),
processorRef.state.undoManager));
}*/
}
void WebViewPluginAudioProcessorEditor::paint(Graphics& g)
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
}
void WebViewPluginAudioProcessorEditor::resized()
{
if (webComponent == nullptr) return;
webComponent->setBounds(getLocalBounds());
}

149
Source/PluginEditor.h Normal file
View File

@ -0,0 +1,149 @@
/*
==============================================================================
PluginEditor.h
Created: 4 Nov 2025 6:20:46pm
Author: mickl
==============================================================================
*/
#pragma once
#include <JuceHeader.h>
#include "PluginProcessor.h"
extern const String localDevServerAddress;
std::optional<WebBrowserComponent::Resource> getResource(const String& url);
//==============================================================================
class SinglePageBrowser : public WebBrowserComponent
{
public:
using WebBrowserComponent::WebBrowserComponent;
// Prevent page loads from navigating away from our single page web app
bool pageAboutToLoad(const String& newURL) override;
bool pageisLoaded = false;
void pageFinishedLoading(const String& newURL) override {
pageisLoaded = true;
}
};
//==============================================================================
class WebViewPluginAudioProcessorEditor : public AudioProcessorEditor, private Timer
{
public:
explicit WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor&);
~WebViewPluginAudioProcessorEditor() {
delete webComponent;
for (auto& attatchments : slider_attatchments) {
delete attatchments;
}
for (auto& relays : slider_relays) {
delete relays;
}
for (auto& attatchments : toggle_attatchments) {
delete attatchments;
}
for (auto& relays : toggle_relays) {
delete relays;
}
}
std::optional<WebBrowserComponent::Resource> getResource(const String& url);
//==============================================================================
void paint(Graphics&) override;
void resized() override;
int getControlParameterIndex(Component&) override
{
return controlParameterIndexReceiver.getControlParameterIndex();
}
void timerCallback() override
{
if(webComponent->pageisLoaded){
webComponent->pageisLoaded = false;
reload_count = 5;
}
if (reload_count) {
if (--reload_count == 0) {
for (auto* slider : slider_attatchments) {
slider->sendInitialUpdate();
}
for (auto* toggle : toggle_attatchments) {
toggle->sendInitialUpdate();
}
/*for (int i = 0; i < processorRef.parameters.sliderIds.size(); ++i) {
slider_attatchments.push_back(new
WebSliderParameterAttachment(
*processorRef.state.getParameter(processorRef.parameters.sliderIds[i]),
*slider_relays.back(),
processorRef.state.undoManager));
}
for (int i = 0; i < processorRef.parameters.toggleIds.size(); ++i) {
toggle_attatchments.push_back(new
WebToggleButtonParameterAttachment(
*processorRef.state.getParameter(processorRef.parameters.toggleIds[i]),
*toggle_relays.back(),
processorRef.state.undoManager));
}*/
}
}
static constexpr size_t numFramesBuffered = 5;
SpinLock::ScopedLockType lock{ processorRef.midiLock };
static int64 callbackCounter = 0;
processorRef.new_midi = false;
juce::Array<var> notes;
int voice_num = 0;
for (auto& voice : processorRef.shifter.voices) {
if (voice.onoff_) {
auto obj = new DynamicObject();
obj->setProperty("voice", voice_num);
obj->setProperty("midi", voice.GetMidiNote());
notes.add(var(obj));
}
voice_num++;
}
DynamicObject::Ptr d(new DynamicObject());
d->setProperty("notes", notes);
webComponent->emitEventIfBrowserIsVisible("midNoteData", d.get());
d->clear();
if (processorRef.shifter.GetAutoTuneEnable()) {
d->setProperty("input_pitch", processorRef.shifter.getInputPitch());
d->setProperty("output_pitch", processorRef.shifter.getOutputPitch());
}
else {
d->setProperty("input_pitch", -1);
d->setProperty("output_pitch", -1);
}
webComponent->emitEventIfBrowserIsVisible("autoTuneData", d.get());
}
private:
WebViewPluginAudioProcessor& processorRef;
std::vector<WebSliderRelay*> slider_relays;
std::vector< WebSliderParameterAttachment*> slider_attatchments;
std::vector<WebToggleButtonRelay*> toggle_relays;
std::vector< WebToggleButtonParameterAttachment*> toggle_attatchments;
WebControlParameterIndexReceiver controlParameterIndexReceiver;
SinglePageBrowser* webComponent = nullptr;
std::deque<Array<var>> spectrumDataFrames;
int reload_count = 0;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessorEditor)
};

109
Source/PluginProcessor.cpp Normal file
View File

@ -0,0 +1,109 @@
/*
==============================================================================
PluginProcessor.cpp
Created: 4 Nov 2025 6:20:37pm
Author: mickl
==============================================================================
*/
#include "PluginProcessor.h"
//==============================================================================
WebViewPluginAudioProcessor::WebViewPluginAudioProcessor(AudioProcessorValueTreeState::ParameterLayout layout)
: AudioProcessor(BusesProperties()
.withInput("Input", juce::AudioChannelSet::stereo(), true)
.withOutput("Output", juce::AudioChannelSet::stereo(), true)
),
parameters(layout),
state(*this, nullptr, "STATE", std::move(layout))
{
shifter.Init(48000.0f, 48);
shifter.SetFormantPreserve(state.getParameterAsValue("formantPreserve").getValue());
shifter.SetAutoTuneSpeed(state.getParameterAsValue("autoTuneSpeed").getValue());
shifter.SetAutoTuneDepth(state.getParameterAsValue("autoTuneDepth").getValue());
shifter.SetPortamentoTime(state.getParameterAsValue("portTime").getValue());
}
//==============================================================================
void WebViewPluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
const auto channels = std::max(getTotalNumInputChannels(), getTotalNumOutputChannels());
shifter.Init((float)sampleRate, samplesPerBlock);
if (channels == 0)
return;
filter.prepare({ sampleRate, (uint32_t)samplesPerBlock, (uint32_t)channels });
filter.reset();
}
bool WebViewPluginAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const
{
if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
return false;
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
return true;
}
void WebViewPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer,
juce::MidiBuffer& midi)
{
juce::ScopedNoDenormals noDenormals;
const auto totalNumInputChannels = getTotalNumInputChannels();
const auto totalNumOutputChannels = getTotalNumOutputChannels();
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear(i, 0, buffer.getNumSamples());
shifter.SetFormantPreserve(state.getParameterAsValue("formantPreserve").getValue());
shifter.SetAutoTuneSpeed(state.getParameterAsValue("autoTuneSpeed").getValue());
shifter.SetAutoTuneDepth(state.getParameterAsValue("autoTuneDepth").getValue());
shifter.SetPortamentoTime(state.getParameterAsValue("portTime").getValue());
shifter.SetHarmonyMix(state.getParameterAsValue("harmonyMix").getValue());
shifter.SetAutoTuneEnable(state.getParameterAsValue("autoTuneEnabled").getValue());
shifter.SetFreeze(state.getParameterAsValue("freezeEnabled").getValue());
shifter.SetFreezePitchAdjust(state.getParameterAsValue("freezePitch").getValue());
shifter.SetFreezeVolume(state.getParameterAsValue("freezeVolume").getValue());
shifter.SetPanWidth(state.getParameterAsValue("panWidth").getValue());
juce::AudioBuffer<float> const_buff;
const_buff.makeCopyOf(buffer);
shifter.Process(const_buff.getArrayOfReadPointers(), (float**)buffer.getArrayOfWritePointers(), buffer.getNumSamples());
for (const auto metadata : midi)
{
const auto msg = metadata.getMessage();
if (msg.isNoteOn()) {
shifter.AddMidiNote(msg.getNoteNumber());
new_midi = true;
}
else if (msg.isNoteOff()) {
shifter.RemoveMidiNote(msg.getNoteNumber());
new_midi = true;
}
}
}
//==============================================================================
void WebViewPluginAudioProcessor::getStateInformation(juce::MemoryBlock& destData)
{
auto out_state = state.copyState();
std::unique_ptr<juce::XmlElement> xml(out_state.createXml());
copyXmlToBinary(*xml, destData);
}
void WebViewPluginAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
{
std::unique_ptr<juce::XmlElement> xmlState(getXmlFromBinary(data, sizeInBytes));
if (xmlState.get() != nullptr && xmlState->hasTagName(state.state.getType()))
state.replaceState(juce::ValueTree::fromXml(*xmlState));
}

174
Source/PluginProcessor.h Normal file
View File

@ -0,0 +1,174 @@
/*
==============================================================================
PluginProcessor.h
Created: 4 Nov 2025 6:20:37pm
Author: mickl
==============================================================================
*/
#pragma once
#include <JuceHeader.h>
#include "Shifter.h"
class WebViewPluginAudioProcessor : public AudioProcessor
{
public:
//==============================================================================
WebViewPluginAudioProcessor(AudioProcessorValueTreeState::ParameterLayout layout);
//==============================================================================
void prepareToPlay(double sampleRate, int samplesPerBlock) override;
void releaseResources() override {}
bool isBusesLayoutSupported(const BusesLayout& layouts) const override;
void processBlock(AudioBuffer<float>&, MidiBuffer&) override;
using AudioProcessor::processBlock;
//==============================================================================
const String getName() const override { return JucePlugin_Name; }
bool acceptsMidi() const override { return false; }
bool producesMidi() const override { return false; }
bool isMidiEffect() const override { return false; }
double getTailLengthSeconds() const override { return 0.0; }
//==============================================================================
int getNumPrograms() override { return 1; }
int getCurrentProgram() override { return 0; }
void setCurrentProgram(int) override {}
const String getProgramName(int) override { return {}; }
void changeProgramName(int, const String&) override {}
//==============================================================================
void getStateInformation(MemoryBlock& destData) override;
void setStateInformation(const void* data, int sizeInBytes) override;
bool new_midi = false;
struct Parameters
{
public:
explicit Parameters(AudioProcessorValueTreeState::ParameterLayout& layout)
{
sliderIds.push_back("formantPreserve");
addToLayout<AudioParameterFloat>(layout,
ParameterID{ "formantPreserve" },
"Formant Preserve",
NormalisableRange<float> {0.0f, 1.0f, .01f},
.5f);
sliderIds.push_back("autoTuneDepth");
addToLayout<AudioParameterFloat>(layout,
ParameterID("autoTuneDepth"),
"AutoTune Depth",
NormalisableRange<float> {0.0f, 1.1f, .01f},
.5f);
sliderIds.push_back("autoTuneSpeed");
addToLayout<AudioParameterFloat>(layout,
ParameterID("autoTuneSpeed"),
"AutoTune Speed",
NormalisableRange<float> {0.001f, 0.1f, .001f},
.5f);
sliderIds.push_back("harmonyMix");
addToLayout<AudioParameterFloat>(layout,
ParameterID("harmonyMix"),
"Harmony Mix",
NormalisableRange<float> {0.0f, 1.0f, .01f},
.01f);
sliderIds.push_back("portTime");
addToLayout<AudioParameterFloat>(layout,
ParameterID("portTime"),
"Portamento Speed",
NormalisableRange<float> {0.001f, 0.2f, .001f},
.01f);
sliderIds.push_back("freezePitch");
addToLayout<AudioParameterFloat>(layout,
ParameterID("freezePitch"),
"Freeze pitch",
NormalisableRange<float> {-12.0f, 12.0f, 1.00f},
0.0f);
sliderIds.push_back("freezeVolume");
addToLayout<AudioParameterFloat>(layout,
ParameterID("freezeVolume"),
"Freeze Volume",
NormalisableRange<float> {0.0f, 1.0f, .01f},
0.5f);
sliderIds.push_back("panWidth");
addToLayout<AudioParameterFloat>(layout,
ParameterID("panWidth"),
"Pan Width",
NormalisableRange<float> {0.0f, 1.0f, .01f},
0.5f);
toggleIds.push_back("autoTuneEnabled");
addToLayout<AudioParameterBool>(layout,
ParameterID("autoTuneEnabled"),
"AutoTune Enabled",
false);
toggleIds.push_back("freezeEnabled");
addToLayout<AudioParameterBool>(layout,
ParameterID("freezeEnabled"),
"Freeze Enabled",
false);
}
/*AudioParameterFloat& formantPreserve;
AudioParameterFloat& autoTuneSpeed;
AudioParameterFloat& autoTuneDepth;
AudioParameterFloat& portTime;*/
std::vector<juce::String> sliderIds;
std::vector<juce::String> toggleIds;
/*AudioParameterBool& mute;
AudioParameterChoice& filterType;*/
private:
template <typename Param>
static void add(AudioProcessorParameterGroup& group, std::unique_ptr<Param> param)
{
group.addChild(std::move(param));
}
template <typename Param>
static void add(AudioProcessorValueTreeState::ParameterLayout& group, std::unique_ptr<Param> param)
{
group.add(std::move(param));
}
template <typename Param, typename Group, typename... Ts>
static Param& addToLayout(Group& layout, Ts&&... ts)
{
auto param = std::make_unique<Param>(std::forward<Ts>(ts)...);
auto& ref = *param;
add(layout, std::move(param));
return ref;
}
};
Parameters parameters;
AudioProcessorValueTreeState state;
SpinLock midiLock;
/*std::vector<int> spectrumData = [] { return std::vector<int>(256, 0.0f); }();
SpinLock spectrumDataLock;
SpectralBars spectralBars;*/
dsp::LadderFilter<float> filter;
Shifter shifter;
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessor)
};

View File

@ -6,303 +6,459 @@
#define PI_F 3.1415927410125732421875f
#endif
void Shifter::SetAutoTuneSpeed(float val) {
out_midi_smoother.SetTimeConstant(val);
}
void Shifter::SetAutoTuneDepth(float val) {
out_midi_smoother.SetDepth(val);
}
static inline float mtof(float m)
{
return powf(2, (m - 69.0f) / 12.0f) * 440.0f;
return powf(2, (m - 69.0f) / 12.0f) * 440.0f;
}
static inline bool float_equal(float one, float two) {
return abs(one - two) < 1e-5f;
return abs(one - two) < 1e-5f;
}
void Shifter::Init()
void Shifter::Init(float samplerate, int samplesPerBlock)
{
volume = 1;
helm.setframesize(1024);
helm.setoverlap(1);
for (int i = 0; i < MAX_VOICES; ++i)
{
voices[i].Init(48000);
}
for (int i = 0; i < BUFFER_SIZE; ++i)
{
in_buffer[i] = 0;
out_buffer[0][i] = 0;
out_buffer[1][i] = 0;
}
for (int i = 0; i < 8192; ++i) {
cos_lookup[i] = cos(2 * PI_F * i / 8192.0);
}
sample_rate_ = samplerate;
blocksize = samplesPerBlock;
out_midi_smoother.SetFrameTime((float)256 / samplerate);
volume = 1;
helm.setframesize(1024);
helm.setoverlap(2);
for (int i = 0; i < MAX_VOICES; ++i)
{
voices[i].Init(samplerate);
freeze_voices[i].Init(samplerate);
}
for (int i = 0; i < BUFFER_SIZE; ++i)
{
in_buffer[i] = 0;
out_buffer[0][i] = 0;
out_buffer[1][i] = 0;
}
for (int i = 0; i < 8192; ++i) {
cos_lookup[i] = cos(2 * PI_F * i / 8192.0);
}
in_period = 0;
}
void Shifter::Process(const float* const* in,
float** out,
size_t size)
float** out,
size_t size)
{
DetectPitch(in, out, size);
SetRates();
// for (size_t i = 0; i < size; ++i) {
// out[0][i] = 0;
// }
GetSamples(out, in[0], size);
//for (size_t i = 0; i < size; ++i)
//{
// // out[0][i] = osc.Process();
// // out[0][i] = in[0][i];
// //out[0][i] = out[0][i] + in[0][i];
// out[1][i] = out[0][i];
//}
// }
for (size_t i = 0; i < size; i += 256) {
size_t offset = i;
size_t lefover_size = std::min((size_t)256, size - i);
DetectPitch(in, out, lefover_size, offset);
SetRates();
GetSamples(out, in[0], lefover_size, offset);
}
//for (size_t i = 0; i < size; ++i)
//{
// // out[0][i] = osc.Process();
// // out[0][i] = in[0][i];
// //out[0][i] = out[0][i] + in[0][i];
// out[1][i] = out[0][i];
//}
// }
}
float findMedian(float a, float b, float c) {
if ((a >= b && a <= c) || (a <= b && a >= c))
return a;
else if ((b >= a && b <= c) || (b <= a && b >= c))
return b;
else
return c;
if ((a >= b && a <= c) || (a <= b && a >= c))
return a;
else if ((b >= a && b <= c) || (b <= a && b >= c))
return b;
else
return c;
}
void Shifter::DetectPitch(const float* const* in, float** out, size_t size)
void Shifter::DetectPitch(const float* const* in, float** out, size_t size, size_t offset)
{
// detect current pitch
// pitch_detect.update(in[0], size);
// if(pitch_detect.available())
// {
// float read = pitch_detect.read();
// if(read >= 35 && read <= 2000)
// {
// for(int i = 2; i > 0; --i){
// last_freqs[i] = last_freqs[i-1];
// }
// last_freqs[0] = read;
// }
// }
// detect current pitch
// pitch_detect.update(in[0], size);
// if(pitch_detect.available())
// {
// float read = pitch_detect.read();
// if(read >= 35 && read <= 2000)
// {
// for(int i = 2; i > 0; --i){
// last_freqs[i] = last_freqs[i-1];
// }
// last_freqs[0] = read;
// }
// }
// current_pitch = findMedian(last_freqs[0], last_freqs[1], last_freqs[2]);
// in_period = 1.0 / current_pitch * 48000;
// current_pitch = findMedian(last_freqs[0], last_freqs[1], last_freqs[2]);
// in_period = 1.0 / current_pitch * 48000;
helm.iosamples(in[0], out[0], size);
float period = helm.getperiod();
float fidel = helm.getfidelity();
//DBG("frequency: " << 48000 / period << " fidel: " << fidel);
helm.iosamples(in[0]+offset, out[0]+offset, size);
float period = helm.getperiod();
float fidel = helm.getfidelity();
//DBG("frequency: " << 48000 / period << " fidel: " << fidel);
// Adjustable filter amount (0.0f = no filtering, 1.0f = max filtering)
static float in_period_filter_amount = 0.7f; // You can expose this as a parameter
// Adjustable filter amount (0.0f = no filtering, 1.0f = max filtering)
const float in_period_filter_amount = 0.5f; // You can expose this as a parameter
if (fidel > 0.95) {
// Smoothly filter in_period changes
in_period = in_period * in_period_filter_amount + period * (1.0f - in_period_filter_amount);
}
float in_freq = 48000 / in_period;
int midi = (int)(12 * log2f(in_freq / 440) + 69.5f);
float target_out_period = 48000.0f / mtof(midi);
if (midi != last_autotune_midi) {
last_autotune_midi = midi;
out_period = in_period;
}
if (fidel > 0.95) {
// Smoothly filter in_`period changes
in_period = in_period * in_period_filter_amount + period * (1.0f - in_period_filter_amount);
}
float in_freq = sample_rate_ / in_period;
float error = target_out_period - out_period;
float adjustment = error * out_period_filter_amount;
float midi = (12 * log2f(in_freq / 440) + 69.0f);
//target_out_period = in_period * out_period_filter_amount + target_out_period * (1 - out_period_filter_amount);
out_midi = midi;
out_period += adjustment;
//target_out_period = in_period * out_period_filter_amount + target_out_period * (1 - out_period_filter_amount);
out_midi = out_midi_smoother.update(midi, (int)(midi + .5));
out_period = sample_rate_ / mtof(out_midi);
}
void Shifter::SetRates() {}
float Shifter::GetOutputEnvelopePeriod(int out_voice) {
if (out_voice >= MAX_VOICES) {
return in_period * formant_preserve + out_period *(1.0 - formant_preserve);
}
//TODO add something so that low pitch ratios end up reducing formant_preservation
return in_period * formant_preserve + voices[out_voice].CurrentPeriod() * (1.0 - formant_preserve);
if (out_voice >= MAX_VOICES) {
return in_period * formant_preserve + out_period * (1.0 - formant_preserve);
}
//TODO add something so that low pitch ratios end up reducing formant_preservation
return in_period * formant_preserve + voices[out_voice].CurrentPeriod() * (1.0 - formant_preserve);
}
float Shifter::GetOutputEnvelopePeriodFreeze(int freeze_voice) {
//TODO add something so that low pitch ratios end up reducing formant_preservation
return freeze_period * formant_preserve + freeze_voices[freeze_voice].CurrentPeriod() * (1.0 - formant_preserve);
}
int Shifter::GetPeakIndex() {
int index = in_playhead - in_period * 2;
if (index < 0)
index += BUFFER_SIZE;
static float current_index = 0;
float smooth = 1 / 200.0f;
int diff = in_playhead - current_index;
if (diff < 0)
diff += BUFFER_SIZE;
if (diff < in_period * 2) {
diff = last_max_index - current_index;
if (diff < -(BUFFER_SIZE / 2))
diff += BUFFER_SIZE;
if (diff > BUFFER_SIZE / 2)
diff -= BUFFER_SIZE;
//search for max absolute value
int max_index = -1;
float max_value = -2;
for (int j = 0; j < in_period; ++j)
{
//float val = fabs(in_buffer[index]);
float val = in_buffer[index];
if (val > max_value)
{
max_index = index;
max_value = val;
}
if (++index >= BUFFER_SIZE)
{
index -= BUFFER_SIZE;
}
}
return max_index;
float adjust = (float)diff * smooth;
if (adjust > 1 || adjust < -1) {
int dummy = 0;
}
current_index += adjust;
if ((int)current_index > BUFFER_SIZE) {
current_index -= BUFFER_SIZE;
}
if((int)current_index < 0) {
current_index += BUFFER_SIZE;
}
return (int)current_index;
}
else {
current_index += in_period;
if (current_index > BUFFER_SIZE) {
current_index -= BUFFER_SIZE;
}
}
float threshold = .0075f;
int index = in_playhead - in_period * 2;
if (index < 0)
index += BUFFER_SIZE;
//search for max absolute value
int max_index = -1;
float max_value = -2;
for (int j = 0; j < in_period; ++j)
{
//float val = fabs(in_buffer[index]);
float val = in_buffer[index];
int period_difference = index - last_max_index;
if (period_difference < 0)
period_difference += BUFFER_SIZE;
//prefer peaks near last peak or near next peak
/*if(!((period_difference > in_period * (0-threshold) && period_difference < in_period* (0+threshold)) || (period_difference > in_period * (1-threshold) && period_difference < in_period * (1+threshold)))) {
val *= 0.75f;
}*/
if (val > max_value)
{
max_index = index;
max_value = val;
}
if (++index >= BUFFER_SIZE)
{
index -= BUFFER_SIZE;
}
}
last_max_index = max_index;
return (int)current_index;
}
//void Shifter::AddInterpolatedFrame(int voice, int max_index, float resampling_period) {
// float period_ratio = resampling_period / out_periods[voice];
// float f_index;
// f_index = max_index - resampling_period;
// if (f_index < 0)
// {
// f_index += BUFFER_SIZE;
// }
// float mult = 0;
// int out_index = out_playhead;
// for (int j = 0; j < resampling_period * 2; ++j)
// {
// // mult = .5
// // * (1 - cosf(2 * PI_F * j / (period_to_use * 2 - 1)));
// float interp = f_index - (int)f_index;
// mult = .5
// * (1 - cos_lookup[(int)((float)j / (resampling_period * 2.0) * 8191.0)]);
// float value = ((1 - interp) * in_buffer[(int)f_index] + (interp)*in_buffer[(int)(f_index + 1) % 8192]) * mult;
// out_buffer[0][out_index] += value * (1 - out_panning[voice]);
// out_buffer[1][out_index] += value * out_panning[voice];
//
//
// f_index += period_ratio;
// if (f_index >= BUFFER_SIZE)
// {
// f_index -= BUFFER_SIZE;
// }
// if (++out_index >= BUFFER_SIZE)
// {
// out_index -= BUFFER_SIZE;
// }
// }
//}
void Shifter::AddInterpolatedFrame(int voice, int max_index, float resampling_period) {
float period_ratio = in_period / resampling_period;
float f_index;
f_index = max_index - in_period;
if (f_index < 0)
{
f_index += BUFFER_SIZE;
}
float mult = 0;
int out_index = out_playhead;
for (int j = 0; j < resampling_period * 2; ++j)
{
// mult = .5
// * (1 - cosf(2 * PI_F * j / (period_to_use * 2 - 1)));
float interp = f_index - (int)f_index;
mult = .5 * (1 - cos_lookup[(int)((float)j / (resampling_period * 2.0) * 8191.0)]);
float value = ((1 - interp) * in_buffer[(int)f_index] + (interp)*in_buffer[(int)(f_index + 1) % 8192]) * mult;
if(voice >= MAX_VOICES) {
//value *= volume;
out_buffer[0][out_index] += value;
out_buffer[1][out_index] += value;
} else {
value *= voices[voice].CurrentAmplitude() * volume;
out_buffer[0][out_index] += value * voices[voice].GetPanning(0);
out_buffer[1][out_index] += value * voices[voice].GetPanning(1);
float period_ratio = in_period / resampling_period;
float f_index;
f_index = max_index - in_period;
if (f_index < 0)
{
f_index += BUFFER_SIZE;
}
float mult = 0;
int out_index = out_playhead;
for (int j = 0; j < resampling_period * 2; ++j)
{
// mult = .5
// * (1 - cosf(2 * PI_F * j / (period_to_use * 2 - 1)));
float interp = f_index - (int)f_index;
mult = .5 * (1 - cos_lookup[(int)((float)j / (resampling_period * 2.0) * 8191.0)]);
float value = ((1 - interp) * in_buffer[(int)f_index] + (interp)*in_buffer[(int)(f_index + 1) % 8192]) * mult;
if (voice >= MAX_VOICES) {
//value *= volume;
out_buffer[0][out_index] += value * melody_mix;
out_buffer[1][out_index] += value * melody_mix;
}
else {
value *= voices[voice].CurrentAmplitude() * volume;
out_buffer[0][out_index] += value * voices[voice].GetPanning(0) * harmony_mix;
out_buffer[1][out_index] += value * voices[voice].GetPanning(1) * harmony_mix;
}
f_index += period_ratio;
if (f_index >= BUFFER_SIZE)
{
f_index -= BUFFER_SIZE;
}
if (++out_index >= BUFFER_SIZE)
{
out_index -= BUFFER_SIZE;
}
}
f_index += period_ratio;
if (f_index >= BUFFER_SIZE)
{
f_index -= BUFFER_SIZE;
}
if (++out_index >= BUFFER_SIZE)
{
out_index -= BUFFER_SIZE;
}
}
}
void Shifter::GetSamples(float** output, const float* input, size_t size)
void Shifter::GetSamples(float** output, const float* input, size_t size, size_t offset)
{
for (int i = 0; i < size; ++i)
{
if (freeze_needs_copy) {
freeze_needs_copy = false;
//copy current buffer to freeze buffer
int index = GetPeakIndex();
memset(freeze_buffer, 0, sizeof(freeze_buffer));
CopyInputToFreezeBuffer(index);
//init freeze voices
for (int i = 0; i < MAX_VOICES; ++i) {
//freeze_voices[i].Init(sample_rate_);
if (voices[i].IsActive()) {
freeze_voices[i].Trigger(voices[i].GetMidiNote());
freeze_voices[i].panning = voices[i].panning;
freeze_voices[i].SetPortamentoTime(0.05f);
}
}
}
for (int i = 0; i < size; ++i)
{
//add new samples if necessary
for (int out_p = 0; out_p < MAX_VOICES; ++out_p)
{
if (!voices[out_p].IsActive()) continue;
//add new samples if necessary
for (int out_p = 0; out_p < MAX_VOICES; ++out_p)
{
voices[out_p].Process();
if (voices[out_p].PeriodOverflow())
{
float resampling_period = GetOutputEnvelopePeriod(out_p);
if (!voices[out_p].IsActive()) continue;
if (voices[out_p].PeriodOverflow())
{
float resampling_period = GetOutputEnvelopePeriod(out_p);
//find the start index
//find the start index
int max_index = GetPeakIndex();
//add samples centered on that max
//add samples centered on that max
AddInterpolatedFrame(out_p, max_index, resampling_period);
}
}
if (out_period_counter > out_period)
{
out_period_counter -= out_period;
float resampling_period = GetOutputEnvelopePeriod(MAX_VOICES);
}
}
//add freeze samples if necessary
for (int out_p = 0; out_p < MAX_VOICES; ++out_p)
{
freeze_voices[out_p].Process();
if (!freeze_voices[out_p].IsActive()) continue;
if (freeze_voices[out_p].PeriodOverflow())
{
float resampling_period = GetOutputEnvelopePeriodFreeze(out_p);
//add samples centered on that max
AddFreezeToOutput(out_p, resampling_period);
}
}
if (out_period_counter > out_period)
{
out_period_counter -= out_period;
if (enable_autotune) {
float resampling_period = GetOutputEnvelopePeriod(MAX_VOICES);
//find the start index
int max_index = GetPeakIndex();
//add samples centered on that max
AddInterpolatedFrame(MAX_VOICES, max_index, resampling_period);
}
//add input samples
in_buffer[in_playhead] = input[i];
//find the start index
int max_index = GetPeakIndex();
//output samples, set to 0
for (int ch = 0; ch < 2; ++ch) {
output[ch][i] = out_buffer[ch][out_playhead];
out_buffer[ch][out_playhead] = 0;
}
//add samples centered on that max
AddInterpolatedFrame(MAX_VOICES, max_index, resampling_period);
}
}
//increment playheads
if (++in_playhead >= BUFFER_SIZE)
{
in_playhead -= BUFFER_SIZE;
}
if (++out_playhead >= BUFFER_SIZE)
{
out_playhead -= BUFFER_SIZE;
}
out_period_counter++;
}
//add input samples
in_buffer[in_playhead] = input[i+offset];
//output samples, set to 0
for (int ch = 0; ch < 2; ++ch) {
output[ch][i+offset] = out_buffer[ch][out_playhead];
if (!enable_autotune) {
output[ch][i+offset] += input[i+offset] * melody_mix;
}
out_buffer[ch][out_playhead] = 0;
}
//increment playheads
if (++in_playhead >= BUFFER_SIZE)
{
in_playhead -= BUFFER_SIZE;
}
if (++out_playhead >= BUFFER_SIZE)
{
out_playhead -= BUFFER_SIZE;
}
out_period_counter++;
}
}
void Shifter::AddMidiNote(int note) {
for (int i = 0; i < MAX_VOICES; ++i) {
if (voices[i].IsActive() && voices[i].GetMidiNote() == note) {
return;
}
}
for (int i = 0; i < MAX_VOICES; ++i) {
if (!voices[i].IsActive()) {
for (int i = 0; i < MAX_VOICES; ++i) {
if (voices[i].onoff_ && voices[i].GetMidiNote() == note) {
voices[i].Release();
}
}
for (int i = 0; i < MAX_VOICES; ++i) {
if (!voices[i].onoff_) {
voices[i].Trigger(note);
return;
}
}
return;
}
}
}
void Shifter::RemoveMidiNote(int note) {
for (int i = 0; i < MAX_VOICES; ++i) {
if (voices[i].IsActive() && voices[i].GetMidiNote() == note) {
voices[i].Release();
return;
}
}
for (int i = 0; i < MAX_VOICES; ++i) {
if (voices[i].GetMidiNote() == note) {
voices[i].Release();
}
}
}
void Shifter::SetHarmonyMix(float mix) {
if (mix < .5) {
melody_mix = 1.0f;
harmony_mix = mix * 2.0f;
}
else {
harmony_mix = 1.0f;
melody_mix = (1.0f - mix) * 2.0f;
}
}
void Shifter::CopyInputToFreezeBuffer(int max_index) {
freeze_period = in_period;
float period_ratio = 1;
float f_index;
f_index = max_index - in_period;
if (f_index < 0)
{
f_index += BUFFER_SIZE;
}
float mult = 0;
for (int j = 0; j < in_period * 2; ++j)
{
mult = .5 * (1 - cos_lookup[(int)((float)j / (in_period * 2.0) * 8191.0)]);
float value = in_buffer[(int)f_index] * mult;
freeze_buffer[j] = value;
f_index += 1;
if (f_index >= BUFFER_SIZE)
{
f_index -= BUFFER_SIZE;
}
}
}
void Shifter::AddFreezeToOutput(int voice, float resampling_period) {
float period_ratio = freeze_period / resampling_period;
float f_index;
f_index = 0;
if (f_index < 0)
{
f_index += BUFFER_SIZE;
}
float mult = 0;
int out_index = out_playhead;
for (int j = 0; j < resampling_period * 2; ++j)
{
// mult = .5
// * (1 - cosf(2 * PI_F * j / (period_to_use * 2 - 1)));
float interp = f_index - (int)f_index;
//mult = .5 * (1 - cos_lookup[(int)((float)j / (resampling_period * 2.0) * 8191.0)]);
float value = ((1 - interp) * freeze_buffer[(int)f_index] + (interp)*freeze_buffer[(int)(f_index + 1) % 8192]);
value *= freeze_voices[voice].CurrentAmplitude();
out_buffer[0][out_index] += value * freeze_voices[voice].GetPanning(0) * freeze_volume;
out_buffer[1][out_index] += value * freeze_voices[voice].GetPanning(1) * freeze_volume;
f_index += period_ratio;
if (f_index >= BUFFER_SIZE)
{
f_index -= BUFFER_SIZE;
}
if (++out_index >= BUFFER_SIZE)
{
out_index -= BUFFER_SIZE;
}
}
}
void Shifter::SetFreeze(bool freeze) {
if (!freeze_mode && freeze) {
freeze_needs_copy = true;
}
else if (freeze_mode && !freeze) {
//release freeze voices
for (int i = 0; i < MAX_VOICES; ++i) {
freeze_voices[i].Release();
}
}
freeze_mode = freeze;
}
void Shifter::SetFreezePitchAdjust(float val) {
for(int i = 0; i < MAX_VOICES; ++i) {
freeze_voices[i].SetPitchAdjust(val);
}
}
void Shifter::SetPanWidth(float val) {
for (int i = 0; i < MAX_VOICES; ++i) {
freeze_voices[i].SetPanWidth(val);
voices[i].SetPanWidth(val);
}
}

View File

@ -10,136 +10,232 @@
template <typename T, size_t max_capacity>
class circ_queue {
public:
circ_queue() {
head = buffer;
tail = buffer;
size = 0;
capacity = max_capacity;
}
circ_queue() {
head = buffer;
tail = buffer;
size = 0;
capacity = max_capacity;
}
void push(T val) {
if (size == max_capacity) {
pop();
}
*tail = val;
if (++tail >= buffer + max_capacity) {
tail -= max_capacity;
}
size++;
//*head = val;
}
void push(T val) {
if (size == max_capacity) {
pop();
}
*tail = val;
if (++tail >= buffer + max_capacity) {
tail -= max_capacity;
}
size++;
//*head = val;
}
void clear() {
head = buffer;
tail = buffer;
size = 0;
}
void clear() {
head = buffer;
tail = buffer;
size = 0;
}
T pop() {
if (size > 0) {
T to_ret = *head;
if (++head >= buffer + max_capacity) {
head -= max_capacity;
}
--size;
return to_ret;
}
else {
return T();
}
}
T pop() {
if (size > 0) {
T to_ret = *head;
if (++head >= buffer + max_capacity) {
head -= max_capacity;
}
--size;
return to_ret;
}
else {
return T();
}
}
T& get(int indx) {
T* ret_ptr = head + indx;
if (ret_ptr >= buffer + max_capacity) {
ret_ptr -= max_capacity;
}
return *ret_ptr;
}
T& get(int indx) {
T* ret_ptr = head + indx;
if (ret_ptr >= buffer + max_capacity) {
ret_ptr -= max_capacity;
}
return *ret_ptr;
}
T& operator[](int indx) {
T* ret_ptr = head + indx;
if (ret_ptr >= buffer + max_capacity) {
ret_ptr -= max_capacity;
}
return *ret_ptr;
}
T& operator[](int indx) {
T* ret_ptr = head + indx;
if (ret_ptr >= buffer + max_capacity) {
ret_ptr -= max_capacity;
}
return *ret_ptr;
}
size_t capacity;
// int size() { return capacity; }
size_t size;
T buffer[max_capacity];
T* head;
T* tail;
size_t capacity;
// int size() { return capacity; }
size_t size;
T buffer[max_capacity];
T* head;
T* tail;
};
class MidiPitchSmoother {
public:
MidiPitchSmoother() {
tau = .1;
dt = 2048.0f / 48000.0f;
PcorrPrev = 60.0f;
PtargPrev = 60;
depth = 1.0f;
inputPrev = 0;
}
void SetFrameTime(float frame_time) {
dt = frame_time;
}
void SetDepth(float d) {
// clamp to [0,1]
if (d < 0.0f) d = 0.0f;
if (d > 1.0f) d = 1.0f;
depth = d;
}
void SetTimeConstant(float t) {
tau = t;
}
float update(float Pdet, int Ptarget) {
// Detect large jump (new note)
float diff = Pdet - (int)(Pdet+.5);
if (Ptarget != PtargPrev) {
// Immediately reset to new note
PcorrPrev = diff;
PtargPrev = Ptarget;
inputPrev = Pdet;
return Ptarget + PcorrPrev;
}
PtargPrev = Ptarget;
diff = Pdet - inputPrev;
// Compute smoothing coefficient
float alpha = 1.0 - std::exp(-dt / tau);
// Compute smoothed pitch toward target
float PcorrFull = PcorrPrev + alpha * (0 - PcorrPrev) * depth + (1 - depth) * diff;
// Apply depth: scale the correction amount
inputPrev = Pdet;
PcorrPrev = PcorrFull;
return Ptarget + PcorrFull;
}
private:
float tau; // Time constant (s)
float dt; // Frame time (s)
float PcorrPrev; // Previous corrected pitch (MIDI)
int PtargPrev; // Previous corrected pitch (MIDI)
float depth; // Amount of correction applied [0..1]
float inputPrev;
};
class Shifter {
public:
void Init();
void Process(const float* const* in,
float** out,
size_t size);
void Init(float samplerate, int samplesPerBlock);
void Process(const float* const* in,
float** out,
size_t size);
void AddMidiNote(int note);
void RemoveMidiNote(int note);
void AddMidiNote(int note);
void RemoveMidiNote(int note);
void SetFormantPreserve(float val) { formant_preserve = val; }
void SetAutoTuneSpeed(float val) { out_period_filter_amount = 1 - val; }
void SetAutoTuneSpeed(float val);
void SetAutoTuneDepth(float val);
void SetPortamentoTime(float time) {
for (int i = 0; i < MAX_VOICES; ++i) {
voices[i].SetPortamentoTime(time);
}
}
float getInputPitch() const { return sample_rate_ / in_period; }
float getOutputPitch() const { return sample_rate_ / out_period; }
void SetHarmonyMix(float mix);
void SetAutoTuneEnable(bool enable) { enable_autotune = enable; }
bool GetAutoTuneEnable() { return enable_autotune; }
void SetFreeze(bool);
void SetFreezePitchAdjust(float val);
void SetFreezeVolume(float val) { freeze_volume = val; }
void SetPanWidth(float val);
int out_midi = -1;
float out_midi = 40;
ShifterVoice voices[MAX_VOICES];
ShifterVoice freeze_voices[MAX_VOICES];
private:
void DetectPitch(const float* const* in, float** out, size_t size);
void SetRates();
void GetSamples(float** output, const float* input, size_t size);
float GetOutputEnvelopePeriod(int out_voice);
int GetPeakIndex();
void AddInterpolatedFrame(int voice, int max_index, float period_to_use);
void DetectPitch(const float* const* in, float** out, size_t size, size_t offset);
void SetRates();
void GetSamples(float** output, const float* input, size_t size, size_t offset);
float GetOutputEnvelopePeriod(int out_voice);
float GetOutputEnvelopePeriodFreeze(int freeze_voice);
int GetPeakIndex();
void AddInterpolatedFrame(int voice, int max_index, float period_to_use);
void AddFreezeToOutput(int voice, float resampling_period);
void CopyInputToFreezeBuffer(int);
Helmholtz helm;
// GranularSustain player;
Helmholtz helm;
// GranularSustain player;
int selected_sample;
bool playing;
bool looping;
bool loop_engaged;
float play_head;
float rate_factor;
float sample_freq = 440;
float freq_target = 440;
float last_freq = 440;
double current_pitch = 440;
double smear_thresh = .085;
double smear_step = 0.003;
bool onset_trigger = false;
bool pitch_trigger = false;
int selected_sample;
bool playing;
bool looping;
bool loop_engaged;
float play_head;
float rate_factor;
float sample_freq = 440;
float freq_target = 440;
float last_freq = 440;
double current_pitch = 440;
double smear_thresh = .085;
double smear_step = 0.003;
bool onset_trigger = false;
bool pitch_trigger = false;
float harmony_mix = 0.0f;
float melody_mix = 0.0f;
bool freeze_needs_copy;
int trigger_bank;
int trigger_bank;
circ_queue<float, 3> prev_freqs;
circ_queue<float, 3> prev_freqs;
float formant_preserve = 0;
float formant_preserve = 0;
float volume;
float pitch_adj;
bool last_record;
int record_playhead;
bool dry_wet = false;
bool is_pitched = true;
float last_freqs[3];
float in_buffer[BUFFER_SIZE];
float out_buffer[2][BUFFER_SIZE];
int out_playhead = 0;
int in_playhead = 0;
float volume;
float pitch_adj;
bool last_record;
int record_playhead;
bool dry_wet = false;
bool is_pitched = true;
float last_freqs[3];
float in_buffer[BUFFER_SIZE];
float out_buffer[2][BUFFER_SIZE];
float freeze_buffer[BUFFER_SIZE];
int out_playhead = 0;
int in_playhead = 0;
int last_autotune_midi = -1;
float out_period_filter_amount = 0.7f; // You can expose this as a parameter
ShifterVoice voices[MAX_VOICES];
float out_period = 0; //C3
float in_period = 366.936;
float out_period_counter = 0;
float cos_lookup[8192];
bool freeze_mode = false;
float out_period = 0; //C3
float in_period = 366.936;
float out_period_counter = 0;
float cos_lookup[8192];
float sample_rate_;
int blocksize;
bool enable_autotune = false;
float freeze_period;
float freeze_volume = 1;
int last_max_index = 0;
MidiPitchSmoother out_midi_smoother;
};
#endif

View File

@ -52,606 +52,12 @@
#pragma once
#include "DemoUtilities.h"
#include <JuceHeader.h>
#include "Shifter.h"
#include "PluginEditor.h"
#include "PluginProcessor.h"
//using namespace juce::dsp;
namespace ID
{
#define PARAMETER_ID(str) static const ParameterID str { #str, 1 };
PARAMETER_ID(formantPreserve)
PARAMETER_ID(autoTuneSpeed)
PARAMETER_ID(mute)
PARAMETER_ID(filterType)
#undef PARAMETER_ID
}
class CircularBuffer
{
public:
CircularBuffer(int numChannels, int numSamples)
: buffer(data, (size_t)numChannels, (size_t)numSamples)
{
}
template <typename T>
void push(dsp::AudioBlock<T> b)
{
jassert(b.getNumChannels() == buffer.getNumChannels());
const auto trimmed = b.getSubBlock(b.getNumSamples()
- std::min(b.getNumSamples(), buffer.getNumSamples()));
const auto bufferLength = (int64)buffer.getNumSamples();
for (auto samplesRemaining = (int64)trimmed.getNumSamples(); samplesRemaining > 0;)
{
const auto writeOffset = writeIx % bufferLength;
const auto numSamplesToWrite = std::min(samplesRemaining, bufferLength - writeOffset);
auto destSubBlock = buffer.getSubBlock((size_t)writeOffset, (size_t)numSamplesToWrite);
const auto sourceSubBlock = trimmed.getSubBlock(trimmed.getNumSamples() - (size_t)samplesRemaining,
(size_t)numSamplesToWrite);
destSubBlock.copyFrom(sourceSubBlock);
samplesRemaining -= numSamplesToWrite;
writeIx += numSamplesToWrite;
}
}
template <typename T>
void push(Span<T> s)
{
auto* ptr = s.begin();
dsp::AudioBlock<T> b(&ptr, 1, s.size());
push(b);
}
void read(int64 readIx, dsp::AudioBlock<float> output) const
{
const auto numChannelsToUse = std::min(buffer.getNumChannels(), output.getNumChannels());
jassert(output.getNumChannels() == buffer.getNumChannels());
const auto bufferLength = (int64)buffer.getNumSamples();
for (auto outputOffset = (size_t)0; outputOffset < output.getNumSamples();)
{
const auto inputOffset = (size_t)((readIx + (int64)outputOffset) % bufferLength);
const auto numSamplesToRead = std::min(output.getNumSamples() - outputOffset,
(size_t)bufferLength - inputOffset);
auto destSubBlock = output.getSubBlock(outputOffset, numSamplesToRead)
.getSubsetChannelBlock(0, numChannelsToUse);
destSubBlock.copyFrom(buffer.getSubBlock(inputOffset, numSamplesToRead)
.getSubsetChannelBlock(0, numChannelsToUse));
outputOffset += numSamplesToRead;
}
}
int64 getWriteIndex() const noexcept { return writeIx; }
private:
HeapBlock<char> data;
dsp::AudioBlock<float> buffer;
int64 writeIx = 0;
};
class SpectralBars
{
public:
//template <typename T>
void push(int data)
{
testQueue.push(data);
}
void compute(Span<int> output) {
int index = 0;
for (auto it = output.begin(); it != output.end(); ++it) {
*it = testQueue.get(index++);
}
}
private:
circ_queue<int, 256> testQueue;
};
//==============================================================================
class WebViewPluginAudioProcessor : public AudioProcessor
{
public:
//==============================================================================
WebViewPluginAudioProcessor(AudioProcessorValueTreeState::ParameterLayout layout);
//==============================================================================
void prepareToPlay(double sampleRate, int samplesPerBlock) override;
void releaseResources() override {}
bool isBusesLayoutSupported(const BusesLayout& layouts) const override;
void processBlock(AudioBuffer<float>&, MidiBuffer&) override;
using AudioProcessor::processBlock;
//==============================================================================
const String getName() const override { return JucePlugin_Name; }
bool acceptsMidi() const override { return false; }
bool producesMidi() const override { return false; }
bool isMidiEffect() const override { return false; }
double getTailLengthSeconds() const override { return 0.0; }
//==============================================================================
int getNumPrograms() override { return 1; }
int getCurrentProgram() override { return 0; }
void setCurrentProgram(int) override {}
const String getProgramName(int) override { return {}; }
void changeProgramName(int, const String&) override {}
//==============================================================================
void getStateInformation(MemoryBlock& destData) override;
void setStateInformation(const void* data, int sizeInBytes) override;
struct Parameters
{
public:
explicit Parameters(AudioProcessorValueTreeState::ParameterLayout& layout)
: formantPreserve(addToLayout<AudioParameterFloat>(layout,
ID::formantPreserve,
"Formant Preserve",
NormalisableRange<float> {0.0f, 1.0f, .01f},
.5f)),
autoTuneSpeed(addToLayout<AudioParameterFloat>(layout,
ID::autoTuneSpeed,
"AutoTune Speed",
NormalisableRange<float> {0.0f, 1.0f, .01f},
.5f)),
mute(addToLayout<AudioParameterBool>(layout, ID::mute, "Mute", false)),
filterType(addToLayout<AudioParameterChoice>(layout,
ID::filterType,
"Filter type",
StringArray{ "Low-pass", "High-pass", "Band-pass" },
0))
{
}
AudioParameterFloat& formantPreserve;
AudioParameterFloat& autoTuneSpeed;
AudioParameterBool& mute;
AudioParameterChoice& filterType;
private:
template <typename Param>
static void add(AudioProcessorParameterGroup& group, std::unique_ptr<Param> param)
{
group.addChild(std::move(param));
}
template <typename Param>
static void add(AudioProcessorValueTreeState::ParameterLayout& group, std::unique_ptr<Param> param)
{
group.add(std::move(param));
}
template <typename Param, typename Group, typename... Ts>
static Param& addToLayout(Group& layout, Ts&&... ts)
{
auto param = std::make_unique<Param>(std::forward<Ts>(ts)...);
auto& ref = *param;
add(layout, std::move(param));
return ref;
}
};
Parameters parameters;
AudioProcessorValueTreeState state;
std::vector<int> spectrumData = [] { return std::vector<int>(256, 0.0f); }();
SpinLock spectrumDataLock;
SpectralBars spectralBars;
dsp::LadderFilter<float> filter;
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessor)
Shifter shifter;
};
//==============================================================================
WebViewPluginAudioProcessor::WebViewPluginAudioProcessor(AudioProcessorValueTreeState::ParameterLayout layout)
: AudioProcessor(BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput("Input", juce::AudioChannelSet::stereo(), true)
#endif
.withOutput("Output", juce::AudioChannelSet::stereo(), true)
#endif
),
parameters(layout),
state(*this, nullptr, "STATE", std::move(layout))
{
shifter.Init();
}
//==============================================================================
void WebViewPluginAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
const auto channels = std::max(getTotalNumInputChannels(), getTotalNumOutputChannels());
shifter.Init();
if (channels == 0)
return;
filter.prepare({ sampleRate, (uint32_t)samplesPerBlock, (uint32_t)channels });
filter.reset();
}
bool WebViewPluginAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const
{
if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
return false;
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
return true;
}
void WebViewPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer,
juce::MidiBuffer& midi)
{
juce::ScopedNoDenormals noDenormals;
const auto totalNumInputChannels = getTotalNumInputChannels();
const auto totalNumOutputChannels = getTotalNumOutputChannels();
for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear(i, 0, buffer.getNumSamples());
shifter.SetFormantPreserve(parameters.formantPreserve.get());
shifter.SetAutoTuneSpeed(parameters.autoTuneSpeed.get());
juce::AudioBuffer<float> const_buff;
const_buff.makeCopyOf(buffer);
shifter.Process(const_buff.getArrayOfReadPointers(), (float**)buffer.getArrayOfWritePointers(), buffer.getNumSamples());
for (const auto metadata : midi)
{
const auto msg = metadata.getMessage();
if (msg.isNoteOn()) shifter.AddMidiNote(msg.getNoteNumber());
else if (msg.isNoteOff()) shifter.RemoveMidiNote(msg.getNoteNumber());
}
{
//DBG(shifter.out_midi[MAX_VOICES]);
//push midi note
//spectralBars.push(shifter.out_midi[MAX_VOICES]);
const SpinLock::ScopedTryLockType lock(spectrumDataLock);
if (!lock.isLocked())
return;
spectralBars.compute({ spectrumData.data(), spectrumData.size() });
}
/*for(auto i = 0; i < buffer.getNumSamples(); ++i)
{
bool process = (i % 256) == 0 && i != 0;
for(auto j = 0; j < totalNumInputChannels; ++j)
{
input[j][i] = buffer.getReadPointer(j)[i];
}
}
filter.setCutoffFrequencyHz (parameters.cutoffFreqHz.get());
const auto filterMode = [this]
{
switch (parameters.filterType.getIndex())
{
case 0:
return dsp::LadderFilter<float>::Mode::LPF12;
case 1:
return dsp::LadderFilter<float>::Mode::HPF12;
default:
return dsp::LadderFilter<float>::Mode::BPF12;
}
}();
filter.setMode (filterMode);
auto outBlock = dsp::AudioBlock<float> { buffer }.getSubsetChannelBlock (0, (size_t) getTotalNumOutputChannels());
if (parameters.mute.get())
outBlock.clear();
filter.process (dsp::ProcessContextReplacing<float> (outBlock));
spectralBars.push (Span { buffer.getReadPointer (0), (size_t) buffer.getNumSamples() });
{
const SpinLock::ScopedTryLockType lock (spectrumDataLock);
if (! lock.isLocked())
return;
spectralBars.compute ({ spectrumData.data(), spectrumData.size() });
}*/
}
//==============================================================================
void WebViewPluginAudioProcessor::getStateInformation(juce::MemoryBlock& destData)
{
juce::ignoreUnused(destData);
}
void WebViewPluginAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
{
juce::ignoreUnused(data, sizeInBytes);
}
extern const String localDevServerAddress;
std::optional<WebBrowserComponent::Resource> getResource(const String& url);
//==============================================================================
struct SinglePageBrowser : WebBrowserComponent
{
using WebBrowserComponent::WebBrowserComponent;
// Prevent page loads from navigating away from our single page web app
bool pageAboutToLoad(const String& newURL) override;
};
//==============================================================================
class WebViewPluginAudioProcessorEditor : public AudioProcessorEditor, private Timer
{
public:
explicit WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor&);
std::optional<WebBrowserComponent::Resource> getResource(const String& url);
//==============================================================================
void paint(Graphics&) override;
void resized() override;
int getControlParameterIndex(Component&) override
{
return controlParameterIndexReceiver.getControlParameterIndex();
}
void timerCallback() override
{
static constexpr size_t numFramesBuffered = 5;
SpinLock::ScopedLockType lock{ processorRef.spectrumDataLock };
Array<var> frame;
for (size_t i = 1; i < processorRef.spectrumData.size(); ++i)
frame.add(processorRef.spectrumData[i]);
spectrumDataFrames.clear();
spectrumDataFrames.push_back(std::move(frame));
while (spectrumDataFrames.size() > numFramesBuffered)
spectrumDataFrames.pop_front();
static int64 callbackCounter = 0;
/*if ( spectrumDataFrames.size() == numFramesBuffered
&& callbackCounter++ % (int64) numFramesBuffered)
{*/
webComponent.emitEventIfBrowserIsVisible("spectrumData", var{});
//}
}
private:
WebViewPluginAudioProcessor& processorRef;
WebSliderRelay formantSliderRelay{ "formantSlider" };
WebSliderRelay autoTuneSpeedSliderRelay{ "autoTuneSpeedSlider" };
WebToggleButtonRelay muteToggleRelay{ "muteToggle" };
WebComboBoxRelay filterTypeComboRelay{ "filterTypeCombo" };
WebControlParameterIndexReceiver controlParameterIndexReceiver;
SinglePageBrowser webComponent{ WebBrowserComponent::Options{}
.withBackend(WebBrowserComponent::Options::Backend::webview2)
.withWinWebView2Options(WebBrowserComponent::Options::WinWebView2{}
.withUserDataFolder(File::getSpecialLocation(File::SpecialLocationType::tempDirectory)))
.withNativeIntegrationEnabled()
.withOptionsFrom(formantSliderRelay)
.withOptionsFrom(autoTuneSpeedSliderRelay)
.withOptionsFrom(muteToggleRelay)
.withOptionsFrom(filterTypeComboRelay)
.withOptionsFrom(controlParameterIndexReceiver)
.withNativeFunction("sayHello", [](auto& var, auto complete)
{
complete("Hello " + var[0].toString());
})
.withResourceProvider([this](const auto& url)
{
return getResource(url);
},
URL { localDevServerAddress }.getOrigin()) };
WebSliderParameterAttachment formantAttachment;
WebSliderParameterAttachment autoTuneSpeedAttachment;
WebToggleButtonParameterAttachment muteAttachment;
WebComboBoxParameterAttachment filterTypeAttachment;
std::deque<Array<var>> spectrumDataFrames;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessorEditor)
};
static ZipFile* getZipFile()
{
static auto stream = createAssetInputStream("webviewplugin-gui_1.0.0.zip", AssertAssetExists::no);
if (stream == nullptr)
return nullptr;
static ZipFile f{ stream.get(), false };
return &f;
}
static const char* getMimeForExtension(const String& extension)
{
static const std::unordered_map<String, const char*> mimeMap =
{
{ { "htm" }, "text/html" },
{ { "html" }, "text/html" },
{ { "txt" }, "text/plain" },
{ { "jpg" }, "image/jpeg" },
{ { "jpeg" }, "image/jpeg" },
{ { "svg" }, "image/svg+xml" },
{ { "ico" }, "image/vnd.microsoft.icon" },
{ { "json" }, "application/json" },
{ { "png" }, "image/png" },
{ { "css" }, "text/css" },
{ { "map" }, "application/json" },
{ { "js" }, "text/javascript" },
{ { "woff2" }, "font/woff2" }
};
if (const auto it = mimeMap.find(extension.toLowerCase()); it != mimeMap.end())
return it->second;
jassertfalse;
return "";
}
static String getExtension(String filename)
{
return filename.fromLastOccurrenceOf(".", false, false);
}
static auto streamToVector(InputStream& stream)
{
std::vector<std::byte> result((size_t)stream.getTotalLength());
stream.setPosition(0);
[[maybe_unused]] const auto bytesRead = stream.read(result.data(), result.size());
jassert(bytesRead == (ssize_t)result.size());
return result;
}
std::optional<WebBrowserComponent::Resource> WebViewPluginAudioProcessorEditor::getResource(const String& url)
{
const auto urlToRetrive = url == "/" ? String{ "index.html" }
: url.fromFirstOccurrenceOf("/", false, false);
if (auto* archive = getZipFile())
{
if (auto* entry = archive->getEntry(urlToRetrive))
{
auto stream = rawToUniquePtr(archive->createStreamForEntry(*entry));
auto v = streamToVector(*stream);
auto mime = getMimeForExtension(getExtension(entry->filename).toLowerCase());
return WebBrowserComponent::Resource{ std::move(v),
std::move(mime) };
}
}
if (urlToRetrive == "index.html")
{
auto fallbackIndexHtml = createAssetInputStream("webviewplugin-gui-fallback.html");
return WebBrowserComponent::Resource{ streamToVector(*fallbackIndexHtml),
String { "text/html" } };
}
if (urlToRetrive == "data.txt")
{
WebBrowserComponent::Resource resource;
static constexpr char testData[] = "testdata";
MemoryInputStream stream{ testData, numElementsInArray(testData) - 1, false };
return WebBrowserComponent::Resource{ streamToVector(stream), String { "text/html" } };
}
if (urlToRetrive == "spectrumData.json")
{
Array<var> frames;
for (const auto& frame : spectrumDataFrames)
frames.add(frame);
DynamicObject::Ptr d(new DynamicObject());
d->setProperty("timeResolutionMs", getTimerInterval());
d->setProperty("frames", std::move(frames));
const auto s = JSON::toString(d.get());
MemoryInputStream stream{ s.getCharPointer(), s.getNumBytesAsUTF8(), false };
return WebBrowserComponent::Resource{ streamToVector(stream), String { "application/json" } };
}
return std::nullopt;
}
#if JUCE_ANDROID
// The localhost is available on this address to the emulator
const String localDevServerAddress = "http://10.0.2.2:3000/";
#else
const String localDevServerAddress = "http://localhost:3000/";
#endif
bool SinglePageBrowser::pageAboutToLoad(const String& newURL)
{
return newURL == localDevServerAddress || newURL == getResourceProviderRoot();
}
//==============================================================================
WebViewPluginAudioProcessorEditor::WebViewPluginAudioProcessorEditor(WebViewPluginAudioProcessor& p)
: AudioProcessorEditor(&p), processorRef(p),
formantAttachment(*processorRef.state.getParameter(ID::formantPreserve.getParamID()),
formantSliderRelay,
processorRef.state.undoManager),
autoTuneSpeedAttachment(*processorRef.state.getParameter(ID::autoTuneSpeed.getParamID()),
autoTuneSpeedSliderRelay,
processorRef.state.undoManager),
muteAttachment(*processorRef.state.getParameter(ID::mute.getParamID()),
muteToggleRelay,
processorRef.state.undoManager),
filterTypeAttachment(*processorRef.state.getParameter(ID::filterType.getParamID()),
filterTypeComboRelay,
processorRef.state.undoManager)
{
addAndMakeVisible(webComponent);
//webComponent.goToURL(localDevServerAddress);
webComponent.goToURL (WebBrowserComponent::getResourceProviderRoot());
setSize(500, 500);
startTimerHz(20);
}
//==============================================================================
void WebViewPluginAudioProcessorEditor::paint(Graphics& g)
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
}
void WebViewPluginAudioProcessorEditor::resized()
{
webComponent.setBounds(getLocalBounds());
}
class WebViewPluginAudioProcessorWrapper : public WebViewPluginAudioProcessor
{
@ -661,5 +67,8 @@ public:
}
bool hasEditor() const override { return true; }
AudioProcessorEditor* createEditor() override { return new WebViewPluginAudioProcessorEditor(*this); }
AudioProcessorEditor* createEditor() override {
return new WebViewPluginAudioProcessorEditor(*this);
}
};

View File

@ -52,6 +52,8 @@ http://crca.ucsd.edu/~msp/software.html */
* of work. -msp
*/
#include "mayer_fft.h"
#define REAL float
#define GOOD_TRIG
@ -62,8 +64,7 @@ http://crca.ucsd.edu/~msp/software.html */
#if defined(GOOD_TRIG)
#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
#define TRIG_VARS \
int t_lam=0;
#define TRIG_INIT(k,c,s) \
{ \
int i; \
@ -92,133 +93,21 @@ http://crca.ucsd.edu/~msp/software.html */
#define TRIG_RESET(k,c,s)
#endif
#if defined(FAST_TRIG)
#define TRIG_VARS \
REAL t_c,t_s;
#define TRIG_INIT(k,c,s) \
{ \
t_c = costab[k]; \
t_s = sintab[k]; \
c = 1; \
s = 0; \
}
#define TRIG_NEXT(k,c,s) \
{ \
REAL t = c; \
c = t*t_c - s*t_s; \
s = t*t_s + s*t_c; \
}
#define TRIG_RESET(k,c,s)
#endif
static REAL halsec[20] =
{
0,
0,
.54119610014619698439972320536638942006107206337801,
.50979557910415916894193980398784391368261849190893,
.50241928618815570551167011928012092247859337193963,
.50060299823519630134550410676638239611758632599591,
.50015063602065098821477101271097658495974913010340,
.50003765191554772296778139077905492847503165398345,
.50000941253588775676512870469186533538523133757983,
.50000235310628608051401267171204408939326297376426,
.50000058827484117879868526730916804925780637276181,
.50000014706860214875463798283871198206179118093251,
.50000003676714377807315864400643020315103490883972,
.50000000919178552207366560348853455333939112569380,
.50000000229794635411562887767906868558991922348920,
.50000000057448658687873302235147272458812263401372
};
static REAL costab[20] =
{
.00000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768847,
.92387953251128675612818318939678828682241662586364,
.98078528040323044912618223613423903697393373089333,
.99518472667219688624483695310947992157547486872985,
.99879545620517239271477160475910069444320361470461,
.99969881869620422011576564966617219685006108125772,
.99992470183914454092164649119638322435060646880221,
.99998117528260114265699043772856771617391725094433,
.99999529380957617151158012570011989955298763362218,
.99999882345170190992902571017152601904826792288976,
.99999970586288221916022821773876567711626389934930,
.99999992646571785114473148070738785694820115568892,
.99999998161642929380834691540290971450507605124278,
.99999999540410731289097193313960614895889430318945,
.99999999885102682756267330779455410840053741619428
};
static REAL sintab[20] =
{
1.0000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768846,
.38268343236508977172845998403039886676134456248561,
.19509032201612826784828486847702224092769161775195,
.09801714032956060199419556388864184586113667316749,
.04906767432741801425495497694268265831474536302574,
.02454122852291228803173452945928292506546611923944,
.01227153828571992607940826195100321214037231959176,
.00613588464915447535964023459037258091705788631738,
.00306795676296597627014536549091984251894461021344,
.00153398018628476561230369715026407907995486457522,
.00076699031874270452693856835794857664314091945205,
.00038349518757139558907246168118138126339502603495,
.00019174759731070330743990956198900093346887403385,
.00009587379909597734587051721097647635118706561284,
.00004793689960306688454900399049465887274686668768
};
static REAL coswrk[20] =
{
.00000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768847,
.92387953251128675612818318939678828682241662586364,
.98078528040323044912618223613423903697393373089333,
.99518472667219688624483695310947992157547486872985,
.99879545620517239271477160475910069444320361470461,
.99969881869620422011576564966617219685006108125772,
.99992470183914454092164649119638322435060646880221,
.99998117528260114265699043772856771617391725094433,
.99999529380957617151158012570011989955298763362218,
.99999882345170190992902571017152601904826792288976,
.99999970586288221916022821773876567711626389934930,
.99999992646571785114473148070738785694820115568892,
.99999998161642929380834691540290971450507605124278,
.99999999540410731289097193313960614895889430318945,
.99999999885102682756267330779455410840053741619428
};
static REAL sinwrk[20] =
{
1.0000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768846,
.38268343236508977172845998403039886676134456248561,
.19509032201612826784828486847702224092769161775195,
.09801714032956060199419556388864184586113667316749,
.04906767432741801425495497694268265831474536302574,
.02454122852291228803173452945928292506546611923944,
.01227153828571992607940826195100321214037231959176,
.00613588464915447535964023459037258091705788631738,
.00306795676296597627014536549091984251894461021344,
.00153398018628476561230369715026407907995486457522,
.00076699031874270452693856835794857664314091945205,
.00038349518757139558907246168118138126339502603495,
.00019174759731070330743990956198900093346887403385,
.00009587379909597734587051721097647635118706561284,
.00004793689960306688454900399049465887274686668768
};
#define SQRT2_2 0.70710678118654752440084436210484
#define SQRT2 2*0.70710678118654752440084436210484
void mayer_fht(REAL* fz, int n)
void MayerFFT::fht(REAL* fz, int n)
{
/* REAL a,b;
REAL c1,s1,s2,c2,s3,c3,s4,c4;
REAL f0,g0,f1,g1,f2,g2,f3,g3; */
int k, k1, k2, k3, k4, kx;
REAL* fi, * fn, * gi;
TRIG_VARS;
int t_lam = 0;
for (k1 = 1, k2 = 0; k1 < n; k1++)
{
@ -360,42 +249,42 @@ void mayer_fht(REAL* fz, int n)
} while (k4 < n);
}
void mayer_fft(int n, REAL* real, REAL* imag)
{
REAL a, b, c, d;
REAL q, r, s, t;
int i, j, k;
for (i = 1, j = n - 1, k = n / 2; i < k; i++, j--) {
a = real[i]; b = real[j]; q = a + b; r = a - b;
c = imag[i]; d = imag[j]; s = c + d; t = c - d;
real[i] = (q + t) * .5; real[j] = (q - t) * .5;
imag[i] = (s - r) * .5; imag[j] = (s + r) * .5;
}
mayer_fht(real, n);
mayer_fht(imag, n);
}
//void mayer_fft(int n, REAL* real, REAL* imag)
//{
// REAL a, b, c, d;
// REAL q, r, s, t;
// int i, j, k;
// for (i = 1, j = n - 1, k = n / 2; i < k; i++, j--) {
// a = real[i]; b = real[j]; q = a + b; r = a - b;
// c = imag[i]; d = imag[j]; s = c + d; t = c - d;
// real[i] = (q + t) * .5; real[j] = (q - t) * .5;
// imag[i] = (s - r) * .5; imag[j] = (s + r) * .5;
// }
// mayer_fht(real, n);
// mayer_fht(imag, n);
//}
//
//void mayer_ifft(int n, REAL* real, REAL* imag)
//{
// REAL a, b, c, d;
// REAL q, r, s, t;
// int i, j, k;
// mayer_fht(real, n);
// mayer_fht(imag, n);
// for (i = 1, j = n - 1, k = n / 2; i < k; i++, j--) {
// a = real[i]; b = real[j]; q = a + b; r = a - b;
// c = imag[i]; d = imag[j]; s = c + d; t = c - d;
// imag[i] = (s + r) * 0.5; imag[j] = (s - r) * 0.5;
// real[i] = (q - t) * 0.5; real[j] = (q + t) * 0.5;
// }
//}
void mayer_ifft(int n, REAL* real, REAL* imag)
{
REAL a, b, c, d;
REAL q, r, s, t;
int i, j, k;
mayer_fht(real, n);
mayer_fht(imag, n);
for (i = 1, j = n - 1, k = n / 2; i < k; i++, j--) {
a = real[i]; b = real[j]; q = a + b; r = a - b;
c = imag[i]; d = imag[j]; s = c + d; t = c - d;
imag[i] = (s + r) * 0.5; imag[j] = (s - r) * 0.5;
real[i] = (q - t) * 0.5; real[j] = (q + t) * 0.5;
}
}
void mayer_realfft(int n, REAL* real)
void MayerFFT::realfft(int n, REAL* real)
{
REAL a, b;
int i, j, k;
mayer_fht(real, n);
fht(real, n);
for (i = 1, j = n - 1, k = n / 2; i < k; i++, j--) {
a = real[i];
b = real[j];
@ -404,7 +293,7 @@ void mayer_realfft(int n, REAL* real)
}
}
void mayer_realifft(int n, REAL* real)
void MayerFFT::realifft(int n, REAL* real)
{
REAL a, b;
int i, j, k;
@ -415,5 +304,5 @@ void mayer_realifft(int n, REAL* real)
real[j] = (a - b);
real[i] = (a + b);
}
mayer_fht(real, n);
fht(real, n);
}

View File

@ -3,7 +3,114 @@
#define REAL float
void mayer_realfft(int n, REAL* real);
void mayer_realifft(int n, REAL* real);
//void mayer_realfft(int n, REAL* real);
//void mayer_realifft(int n, REAL* real);
class MayerFFT {
public:
void realfft(int n, REAL* real);
void realifft(int n, REAL* real);
MayerFFT() :halsec{
0,
0,
.54119610014619698439972320536638942006107206337801,
.50979557910415916894193980398784391368261849190893,
.50241928618815570551167011928012092247859337193963,
.50060299823519630134550410676638239611758632599591,
.50015063602065098821477101271097658495974913010340,
.50003765191554772296778139077905492847503165398345,
.50000941253588775676512870469186533538523133757983,
.50000235310628608051401267171204408939326297376426,
.50000058827484117879868526730916804925780637276181,
.50000014706860214875463798283871198206179118093251,
.50000003676714377807315864400643020315103490883972,
.50000000919178552207366560348853455333939112569380,
.50000000229794635411562887767906868558991922348920,
.50000000057448658687873302235147272458812263401372
},
costab{
.00000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768847,
.92387953251128675612818318939678828682241662586364,
.98078528040323044912618223613423903697393373089333,
.99518472667219688624483695310947992157547486872985,
.99879545620517239271477160475910069444320361470461,
.99969881869620422011576564966617219685006108125772,
.99992470183914454092164649119638322435060646880221,
.99998117528260114265699043772856771617391725094433,
.99999529380957617151158012570011989955298763362218,
.99999882345170190992902571017152601904826792288976,
.99999970586288221916022821773876567711626389934930,
.99999992646571785114473148070738785694820115568892,
.99999998161642929380834691540290971450507605124278,
.99999999540410731289097193313960614895889430318945,
.99999999885102682756267330779455410840053741619428
},
sintab{
1.0000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768846,
.38268343236508977172845998403039886676134456248561,
.19509032201612826784828486847702224092769161775195,
.09801714032956060199419556388864184586113667316749,
.04906767432741801425495497694268265831474536302574,
.02454122852291228803173452945928292506546611923944,
.01227153828571992607940826195100321214037231959176,
.00613588464915447535964023459037258091705788631738,
.00306795676296597627014536549091984251894461021344,
.00153398018628476561230369715026407907995486457522,
.00076699031874270452693856835794857664314091945205,
.00038349518757139558907246168118138126339502603495,
.00019174759731070330743990956198900093346887403385,
.00009587379909597734587051721097647635118706561284,
.00004793689960306688454900399049465887274686668768
},
coswrk{
.00000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768847,
.92387953251128675612818318939678828682241662586364,
.98078528040323044912618223613423903697393373089333,
.99518472667219688624483695310947992157547486872985,
.99879545620517239271477160475910069444320361470461,
.99969881869620422011576564966617219685006108125772,
.99992470183914454092164649119638322435060646880221,
.99998117528260114265699043772856771617391725094433,
.99999529380957617151158012570011989955298763362218,
.99999882345170190992902571017152601904826792288976,
.99999970586288221916022821773876567711626389934930,
.99999992646571785114473148070738785694820115568892,
.99999998161642929380834691540290971450507605124278,
.99999999540410731289097193313960614895889430318945,
.99999999885102682756267330779455410840053741619428
},
sinwrk{
1.0000000000000000000000000000000000000000000000000,
.70710678118654752440084436210484903928483593768846,
.38268343236508977172845998403039886676134456248561,
.19509032201612826784828486847702224092769161775195,
.09801714032956060199419556388864184586113667316749,
.04906767432741801425495497694268265831474536302574,
.02454122852291228803173452945928292506546611923944,
.01227153828571992607940826195100321214037231959176,
.00613588464915447535964023459037258091705788631738,
.00306795676296597627014536549091984251894461021344,
.00153398018628476561230369715026407907995486457522,
.00076699031874270452693856835794857664314091945205,
.00038349518757139558907246168118138126339502603495,
.00019174759731070330743990956198900093346887403385,
.00009587379909597734587051721097647635118706561284,
.00004793689960306688454900399049465887274686668768
}
{
}
private:
void fht(REAL* fz, int n);
REAL halsec[20];
REAL costab[20];
REAL sintab[20];
REAL coswrk[20];
REAL sinwrk[20];
};
#endif

View File

@ -18,18 +18,23 @@ static inline float mtof(float m)
void ShifterVoice::Init(float sample_rate) {
portamento_.Init(sample_rate, 0.05f); //default portamento time
amplitude_envelope_.Init(sample_rate);
sample_rate_ = sample_rate;
portamento_.Init(sample_rate_, 0.05f); //default portamento time
amplitude_envelope_.Init(sample_rate_);
amplitude_envelope_.SetAttackTime(0.2f);
amplitude_envelope_.SetDecayTime(0.2f);
amplitude_envelope_.SetReleaseTime(1.0f);
amplitude_envelope_.SetDecayTime(0.1f);
amplitude_envelope_.SetReleaseTime(.05f);
onoff_ = false;
overflow_ = false;
current_midi = 60;
current_period_ = 48000.0f / mtof((float)current_midi);
current_period_ = sample_rate_ / mtof((float)current_midi);
current_amplitude = 0.0f;
period_counter = 0.0f;
panning = 0.5f;
//on reset, make sure envelope is not running
while (amplitude_envelope_.IsRunning()) {
amplitude_envelope_.Process(false);
}
}
@ -40,7 +45,24 @@ void ShifterVoice::Trigger(int midi_note) {
// Retrigger envelope
amplitude_envelope_.Retrigger(false);
onoff_ = true;
float pan_min = 0;
float pan_max = 1;
if(pan_width < .5f)
pan_max = .1 + (pan_width * 2 * .9f);
else
pan_min = (pan_width - .5f) * 2 * .9f;
bool pan_left = rand() % 2;
panning = rand() / (float)RAND_MAX;
panning = pan_min + (panning * (pan_max - pan_min));
if (pan_left) {
panning = .5 - panning * .5f;
}
else {
panning = .5 + panning * .5f;
}
}
void ShifterVoice::Release() {
@ -49,7 +71,7 @@ void ShifterVoice::Release() {
void ShifterVoice::Process() {
current_amplitude = amplitude_envelope_.Process(onoff_);
current_period_ = 48000.0f / mtof(portamento_.Process((float)current_midi));
current_period_ = sample_rate_ / mtof(portamento_.Process((float)current_midi + pitch_adjust));
period_counter++;
overflow_ = period_counter >= current_period_;
if (overflow_) {
@ -88,4 +110,8 @@ float ShifterVoice::GetPanning(int channel) const {
case 1:
return panning > .5 ? 1.0 : panning * 2.0f;
}
}
void ShifterVoice::SetPitchAdjust(float adj) {
pitch_adjust = adj;
}

View File

@ -32,15 +32,22 @@ public:
void SetAdsrTimes(float attack, float decay, float release);
float GetPanning(int channel) const;
int GetMidiNote() const { return current_midi; }
void SetPitchAdjust(float);
void SetPanWidth(float val) { pan_width = val; }
bool onoff_;
float panning;
private:
Port portamento_;
Adsr amplitude_envelope_;
bool onoff_;
bool overflow_;
float sample_rate_;
int current_midi;
float current_period_;
float current_amplitude;
float period_counter;
float panning;
float pitch_adjust = 0.0f;
float pan_width = 0.0f;
};