Skip to content

Commit

Permalink
add audio for contour
Browse files Browse the repository at this point in the history
  • Loading branch information
blechdom committed Nov 9, 2023
1 parent 14d0679 commit cd3b90e
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 76 deletions.
51 changes: 24 additions & 27 deletions src/components/ContourAudioControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,41 @@ import styled from "styled-components";
import {AudioParamsType, KnobRow} from "@/components/FractalPlayer";

type ContourAudioControlsProps = {
rowIndex: number;
fractalRow: number[];
contour: { angle: number; duration: number }[];
audioContext: AudioContext | null;
core: WebRenderer;
playing: boolean;
}

const ContourAudioControls: React.FC<ContourAudioControlsProps> = (
{
rowIndex,
fractalRow,
contour,
audioContext,
core,
playing,
}) => {

const [volume, setVolume] = useState<number>(0);
const [threshold, setThreshold] = useState<number>(0.09);
const [lowest, setLowest] = useState<number>(200);
const [freqScaling, setFreqScaling] = useState<number>(1);
const [highest, setHighest] = useState<number>(6000);
const [smoothing, setSmoothing] = useState<number>(0.02);
const [duration, setDuration] = useState<number>(5);
const [audioParams, setAudioParams] = useState<AudioParamsType>({
volume: 0,
threshold: 0,
highest: 0,
lowest: 0,
smoothing: 0,
freqScaling: 0,
duration: 0,
});

useEffect(() => {
setAudioParams({volume, lowest, highest, threshold, smoothing});
}, [volume, lowest, highest, threshold, smoothing, setAudioParams]);
setAudioParams({volume, freqScaling, highest, threshold, duration});
}, [volume, freqScaling, highest, threshold, duration, setAudioParams]);

return (<>
<KnobRow>
<ContourAudioEngine
rowIndex={rowIndex}
fractalRow={fractalRow}
contour={contour}
audioContext={audioContext}
core={core}
playing={playing}
Expand All @@ -68,20 +65,20 @@ const ContourAudioControls: React.FC<ContourAudioControlsProps> = (
<KnobRow>
<ControlKnob>
<Knob
id={`contour-lowest`}
label={"lowest"}
id={`freqScaling`}
label={"freqScale"}
diameter={30}
labelWidth={30}
fontSize={11}
tooltip={"lowest frequency of the oscillator bank (hz)"}
knobValue={lowest}
tooltip={"scale Frequency by this value"}
knobValue={freqScaling}
step={0.01}
min={0}
max={500}
onKnobInput={setLowest}
max={10}
onKnobInput={setFreqScaling}
/>
</ControlKnob>
<ControlKnob>
{/*<ControlKnob>
<Knob
id={`contour-highest`}
label={"highest"}
Expand Down Expand Up @@ -110,20 +107,20 @@ const ContourAudioControls: React.FC<ContourAudioControlsProps> = (
max={1}
onKnobInput={setThreshold}
/>
</ControlKnob>
</ControlKnob>*/}
<ControlKnob>
<Knob
id={`contour-smoothing`}
label={"smooth"}
id={`contour-duration`}
label={"durScale"}
diameter={30}
labelWidth={30}
fontSize={11}
tooltip={"smoothing of frequency when changing (0.02 = 20ms)"}
knobValue={smoothing}
step={0.01}
tooltip={"duration of frequency when changing (0.02 = 20ms)"}
knobValue={duration}
step={0.1}
min={0}
max={0.5}
onKnobInput={setSmoothing}
max={100}
onKnobInput={setDuration}
/>
</ControlKnob>
</KnobRow>
Expand Down
86 changes: 43 additions & 43 deletions src/components/ContourAudioEngine.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {AudioParamsType} from "@/components/FractalPlayer";
import dynamic from "next/dynamic";
import React, {useEffect, useState} from "react";
import React, {useCallback, useEffect, useState} from "react";
import {el, NodeRepr_t} from "@elemaudio/core";
import WebRenderer from "@elemaudio/web-renderer";
import styled from "styled-components";
Expand All @@ -10,26 +10,26 @@ const OscilloscopeSpectrogram = dynamic(() => import('el-vis-audio').then((mod)
require("events").EventEmitter.defaultMaxListeners = 0;

type AudioEngineProps = {
rowIndex: number;
fractalRow: number[];
contour: { angle: number; duration: number }[];
audioContext: AudioContext | null;
core: WebRenderer;
playing: boolean;
audioParams: AudioParamsType;
}

const AudioEngine: React.FC<AudioEngineProps> = ({
rowIndex,
fractalRow,
contour,
audioContext,
core,
playing,
audioParams: {volume, lowest, highest, threshold, smoothing}
audioParams: {volume, freqScaling, highest, threshold, duration}
}) => {

const [audioVizData, setAudioVizData] = useState<any>();
const [fftVizData, setFftVizData] = useState<any>();
const [ampScale, setAmpScale] = useState<number>(0);
const [frequency, setFrequency] = useState<number>(220);
const [contourStarted, setContourStarted] = useState<boolean>(false);
const [sequencerId, setSequencerId] = useState<any>();

useEffect(() => {
return () => {
Expand All @@ -40,6 +40,7 @@ const AudioEngine: React.FC<AudioEngineProps> = ({
}, [audioContext]);

useEffect(() => {
if (!contourStarted) startContour();
if (audioContext) {
const SignalSynth = (signal: NodeRepr_t) => {
if (playing && signal && core) {
Expand All @@ -52,48 +53,47 @@ const AudioEngine: React.FC<AudioEngineProps> = ({
core.render(synth, synth);
}
};

const Resynth = () => {
let accum = 0;
const linearRange = Math.log10(highest) - Math.log10(lowest);
const linearInterval = linearRange / fractalRow.length;

const allVoices = [...Array(fractalRow.length)].map((_, i) => {
const amplitude = fractalRow[i] > threshold ? fractalRow[i] : 0;
const key = `osc-freq-${i}`;
const linearFreq = Math.log10(lowest) + (i * linearInterval);
const freq = 10 ** linearFreq;

if (freq < audioContext.sampleRate / 2) {
accum += amplitude;
const freqSignal = el.const({key, value: freq});
const ampSignal = el.const({key: `osc-amp-${i}`, value: amplitude});
const smoothFreqSignal = el.smooth(el.tau2pole(smoothing), freqSignal);
const smoothAmpSignal = el.smooth(el.tau2pole(smoothing), ampSignal);
return el.mul(el.cycle(smoothFreqSignal), smoothAmpSignal);
} else {
return el.const({key, value: 0});
}
});

const addMany = (ins: NodeRepr_t[]): NodeRepr_t => {
return el.add(...ins) as NodeRepr_t;
};
const rowMult = accum !== 0 ? 1 / accum : 0;
setAmpScale(rowMult);
const rowAmp = el.const({key: "row-gain", value: rowMult});
const smoothRowAmp = el.smooth(el.tau2pole(smoothing), rowAmp);
return el.mul(addMany(allVoices as NodeRepr_t[]), smoothRowAmp) as NodeRepr_t;
}

const ContourSynth = el.cycle(el.sm(el.const({key: 'ex2:mix', value: frequency})));
if (playing) {
audioContext.resume();
if (fractalRow?.length > 0) SignalSynth(Resynth());
SignalSynth(ContourSynth);
} else {
setContourStarted(false);
setFrequency(200);
audioContext.suspend();
}
}
}, [playing, volume, lowest, highest, threshold, fractalRow, audioContext, core, smoothing]);
}, [playing, volume, freqScaling, highest, threshold, contour, audioContext, core, frequency]);

const startContour = useCallback(() => {
if (!playing) {
clearInterval(sequencerId)
setContourStarted(false);
} else {
setContourStarted(true);
let elapsedTime = 0;
let freq = frequency;
contour.forEach((segment, i) => {
elapsedTime += (segment.duration * duration);
setTimeout(() => {
freq += ((segment.angle - 180) * freqScaling);
setFrequency(freq);
}, elapsedTime);
});

// start setIntervals
//let freq = frequency;
//const i = 0;
//const intervalId = setInterval(() => {

//setFrequency(freq);
//freq += (contour[i].angle - 180);
//i++;
//}, contour[i].duration * 500);
//setSequencerId(intervalId);
}
}, [playing, contour]);


core?.on("scope", function (e) {
if (e.source === `scope-contour`) {
Expand Down
10 changes: 4 additions & 6 deletions src/components/FractalPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export type AudioParamsType = {
volume: number;
threshold: number;
highest: number;
lowest: number;
smoothing: number;
freqScaling: number;
duration: number;
}

const FractalPlayer: React.FC<FractalPlayerProps> = ({
Expand Down Expand Up @@ -110,7 +110,6 @@ const FractalPlayer: React.FC<FractalPlayerProps> = ({
setContour(newContour.soundControlList);
}
}
console.log("marching squares");
}
}, [tolerance, rawFractalData, showContour]);

Expand Down Expand Up @@ -362,16 +361,15 @@ const FractalPlayer: React.FC<FractalPlayerProps> = ({
diameter={30}
labelWidth={30}
fontSize={11}
tooltip={"tolerance of contour smoothing"}
tooltip={"tolerance of contour duration"}
knobValue={tolerance}
step={0.1}
min={0}
max={5}
onKnobInput={setTolerance}
/>
<ContourAudioControls
rowIndex={rowIndex}
fractalRow={rowIndex === -1 ? Array(size).fill(0) : playheadFractalData[rowIndex]}
contour={contour}
audioContext={audioContext}
core={core}
playing={playing}
Expand Down

0 comments on commit cd3b90e

Please sign in to comment.