diff --git a/package-lock.json b/package-lock.json index 49470ee..d559332 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@mantine/core": "^7.1.5", "@mantine/form": "^7.1.7", "@mantine/hooks": "^7.1.5", - "@p5-wrapper/react": "^4.2.0", + "@p5-wrapper/react": "^4.4.0", "@reduxjs/toolkit": "^1.9.7", "@tabler/icons-react": "^2.39.0", "clsx": "^2.0.0", @@ -1082,12 +1082,12 @@ } }, "node_modules/@p5-wrapper/react": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@p5-wrapper/react/-/react-4.2.0.tgz", - "integrity": "sha512-LOTd/1W8sPiXo7/U0PwapsoOf74DQAFMibovvhrB+aImYNXbg+5xoAadnmgC28OBySeBNKXwchWhF1ctf6Pnpw==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@p5-wrapper/react/-/react-4.4.0.tgz", + "integrity": "sha512-4s6KEVb0of3s959tmmQ0Xc77v8Y1ZDw6sbjKR+E8Qdn5oLMfat7Wah5Az9Cs2AzljK3HQcz7WFhel5qBTKJyuQ==", "dependencies": { - "microdiff": "^1.3.2", - "p5": "^1.6.0" + "microdiff": "^1.4.0", + "p5": ">=1.4.1 <2.0.0" }, "peerDependencies": { "react": ">= 18.2.0", @@ -2919,9 +2919,9 @@ } }, "node_modules/microdiff": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.3.2.tgz", - "integrity": "sha512-pKy60S2febliZIbwdfEQKTtL5bLNxOyiRRmD400gueYl9XcHyNGxzHSlJWn9IMHwYXT0yohPYL08+bGozVk8cQ==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.4.0.tgz", + "integrity": "sha512-OBKBOa1VBznvLPb/3ljeJaENVe0fO0lnWl77lR4vhPlQD71UpjEoRV5P0KdQkcjbFlBu1Oy2mEUBMU3wxcBAGg==" }, "node_modules/micromatch": { "version": "4.0.5", @@ -4985,12 +4985,12 @@ } }, "@p5-wrapper/react": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@p5-wrapper/react/-/react-4.2.0.tgz", - "integrity": "sha512-LOTd/1W8sPiXo7/U0PwapsoOf74DQAFMibovvhrB+aImYNXbg+5xoAadnmgC28OBySeBNKXwchWhF1ctf6Pnpw==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@p5-wrapper/react/-/react-4.4.0.tgz", + "integrity": "sha512-4s6KEVb0of3s959tmmQ0Xc77v8Y1ZDw6sbjKR+E8Qdn5oLMfat7Wah5Az9Cs2AzljK3HQcz7WFhel5qBTKJyuQ==", "requires": { - "microdiff": "^1.3.2", - "p5": "^1.6.0" + "microdiff": "^1.4.0", + "p5": ">=1.4.1 <2.0.0" } }, "@reduxjs/toolkit": { @@ -6300,9 +6300,9 @@ "dev": true }, "microdiff": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.3.2.tgz", - "integrity": "sha512-pKy60S2febliZIbwdfEQKTtL5bLNxOyiRRmD400gueYl9XcHyNGxzHSlJWn9IMHwYXT0yohPYL08+bGozVk8cQ==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/microdiff/-/microdiff-1.4.0.tgz", + "integrity": "sha512-OBKBOa1VBznvLPb/3ljeJaENVe0fO0lnWl77lR4vhPlQD71UpjEoRV5P0KdQkcjbFlBu1Oy2mEUBMU3wxcBAGg==" }, "micromatch": { "version": "4.0.5", diff --git a/package.json b/package.json index 40e8247..68dc9dd 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "@mantine/core": "^7.1.5", "@mantine/form": "^7.1.7", "@mantine/hooks": "^7.1.5", - "@p5-wrapper/react": "^4.2.0", + "@p5-wrapper/react": "^4.4.0", "@reduxjs/toolkit": "^1.9.7", "@tabler/icons-react": "^2.39.0", "clsx": "^2.0.0", diff --git a/src/components/CreateOutput/CreateOutput.tsx b/src/components/CreateOutput/CreateOutput.tsx new file mode 100644 index 0000000..382ba37 --- /dev/null +++ b/src/components/CreateOutput/CreateOutput.tsx @@ -0,0 +1,20 @@ +import React, { ReactNode, useEffect } from "react" +import treingvbluesberber from "../../assets/music/treingvbluesberber.mp3" +import P5WaveFormSketchWrapper from "../../pages/patternmaker-page/components/P5WaveFormSketchWrapper" +import * as Tone from "tone" + +interface CreateOutputProps { + children: ReactNode +} +const channel = new Tone.Channel(-0.25, -1) +const output = new Tone.Volume(-12).toDestination() +const lpFilter = new Tone.Filter(8000, "lowpass", -48).connect(output) +const hpFilter = new Tone.Filter(0, "highpass").connect(lpFilter) + +function CreateOutput({ children }: CreateOutputProps) { + // console.log("hoi") + + return
{children}
+} + +export default CreateOutput diff --git a/src/components/WaveSurferPlayer/BlankWaveSurfer.tsx b/src/components/WaveSurferPlayer/BlankWaveSurfer.tsx index a98d281..d422a4e 100644 --- a/src/components/WaveSurferPlayer/BlankWaveSurfer.tsx +++ b/src/components/WaveSurferPlayer/BlankWaveSurfer.tsx @@ -47,6 +47,7 @@ const BlankWaveSurfer: React.FC = (props) => { const [loop, setLoop] = useState(false) const [activeRegion, setActiveRegion] = useState(null) const [cuePoint, setCuePoint] = useState(null) + const [pitchValue, setPitchValue] = useState(0.5) useEffect(() => { if (!wavesurfer) return @@ -56,13 +57,13 @@ const BlankWaveSurfer: React.FC = (props) => { // WAVESURFER INIT useEffect(() => { if (!wavesurfer || !wsRegions) return - // setCurrentTime(0) - const subscriptions = [ wavesurfer.on("play", () => setIsPlaying(true)), wavesurfer.on("pause", () => setIsPlaying(false)), - wavesurfer.on("timeupdate", (currentTime) => setCurrentTime(currentTime)), - wavesurfer.on("zoom", (e) => { + wavesurfer.on("timeupdate", (currentTime: number) => + setCurrentTime(currentTime), + ), + wavesurfer.on("zoom", (e: number) => { setZoom(e), setCurrentTime(currentTime) }), ] @@ -142,12 +143,13 @@ const BlankWaveSurfer: React.FC = (props) => { // FOLLOW useEffect(() => { - wavesurfer?.setOptions({ autoScroll: follow }) + wavesurfer?.setOptions({ autoScroll: follow, autoCenter: follow }) }, [follow, wavesurfer]) // PLAY const onPlayClick = useCallback(() => { if (!wavesurfer) return + console.log(wavesurfer.isPlaying()) wavesurfer.isPlaying() ? wavesurfer.pause() : wavesurfer?.playPause() }, [wavesurfer]) @@ -203,6 +205,8 @@ const BlankWaveSurfer: React.FC = (props) => { changePitch={(e: number) => { if (e > 0.07) wavesurfer!.setPlaybackRate(e, false) }} + setPitchValue={setPitchValue} + pitchValue={pitchValue} /> = (props) => { wavesurfer?.zoom(zoom + 5)} /> + {/* + + Hoi ik zit in de doos + + */} ) } diff --git a/src/components/WaveSurferPlayer/PitchSlider.tsx b/src/components/WaveSurferPlayer/PitchSlider.tsx index dcdc745..00a4016 100644 --- a/src/components/WaveSurferPlayer/PitchSlider.tsx +++ b/src/components/WaveSurferPlayer/PitchSlider.tsx @@ -1,17 +1,21 @@ -import { useState } from "react" import { Group, Stack, rem } from "@mantine/core" import { useMove } from "@mantine/hooks" interface PitchSliderProps { changePitch: (y: number) => void + setPitchValue: (y: number) => void + pitchValue: number } -const PitchSlider: React.FC = ({ changePitch }) => { - const [value, setValue] = useState(0.5) +const PitchSlider: React.FC = ({ + changePitch, + setPitchValue, + pitchValue, +}) => { const { ref } = useMove(({ y }) => setter(y)) const setter = (y: number) => { - setValue(y) + setPitchValue(y) // changePitch(y * 0.25 + 0.875); // changePitch(y * 0.5 + 0.75); // changePitch(y * 1 + 0.5); @@ -36,7 +40,7 @@ const PitchSlider: React.FC = ({ changePitch }) => {
= ({ audiofile }) => { + const [isPlaying, setIsPlaying] = useState(false) + const audioRef = useRef(null) + const canvasRef = useRef(null) + const animationRef = useRef(null) + + const startAudio = async () => { + try { + const audioContext = new window.AudioContext() + const audioElement = audioRef.current + const canvasElement = canvasRef.current + + if (!audioElement || !canvasElement) return + + const sourceNode = audioContext.createMediaElementSource(audioElement) + const analyserNode = audioContext.createAnalyser() + analyserNode.fftSize = 2048 + const javascriptNode = audioContext.createScriptProcessor(2048, 1, 1) + + sourceNode.connect(analyserNode) + analyserNode.connect(audioContext.destination) + analyserNode.connect(javascriptNode) + javascriptNode.connect(audioContext.destination) + + setIsPlaying(true) + + const draw = () => { + const canvasContext = canvasElement.getContext("2d") + const bufferLength = analyserNode.frequencyBinCount + const dataArray = new Uint8Array(bufferLength) + analyserNode.getByteTimeDomainData(dataArray) + if (!canvasContext) return + canvasContext.clearRect(0, 0, canvasElement.width, canvasElement.height) + canvasContext.fillStyle = "rgb(255, 255, 255)" + canvasContext.fillRect(0, 0, canvasElement.width, canvasElement.height) + canvasContext.lineWidth = 2 + canvasContext.strokeStyle = "rgb(0, 0, 0)" + canvasContext.beginPath() + + const sliceWidth = (canvasElement.width * 1.0) / bufferLength + let x = 0 + + for (let i = 0; i < bufferLength; i++) { + const v = dataArray[i] / 128.0 + const y = (v * canvasElement.height) / 2 + + if (i === 0) { + canvasContext.moveTo(x, y) + } else { + canvasContext.lineTo(x, y) + } + + x += sliceWidth + } + + canvasContext.lineTo(canvasElement.width, canvasElement.height / 2) + canvasContext.stroke() + + animationRef.current = requestAnimationFrame(draw) + } + + audioElement.play() + draw() + } catch (error) { + console.error("Error starting audio:", error) + } + } + + startAudio() + return ( +
+ + +
+ {isPlaying ? "Audio playing..." : ""} +
+ +
+ ) +} + +export default AudioAnalyser diff --git a/src/components/audiocontext/Boombox.tsx b/src/components/audiocontext/Boombox.tsx new file mode 100644 index 0000000..7fababa --- /dev/null +++ b/src/components/audiocontext/Boombox.tsx @@ -0,0 +1,124 @@ +import React, { useState, useEffect } from "react" +import treingvbluesberber from "../../assets/music/treingvbluesberber.mp3" + +const Boombox: React.FC = () => { + const [isPlaying, setIsPlaying] = useState(false) + const [volume, setVolume] = useState(0.5) // Initial volume value + const [filterFrequency, setFilterFrequency] = useState(50) // Initial filter frequency value + const [audioElement, setAudioElement] = useState( + null, + ) + const [audioCtx, setAudioCtx] = useState(null) + const audio = new Audio(treingvbluesberber) + + useEffect(() => { + // Set up audio context when component mounts + const AudioContext = window.AudioContext + const ctx = new AudioContext() + setAudioCtx(ctx) + + setAudioElement(audio) + // Clean up audio context when component unmounts + return () => { + if (ctx.state !== "closed") { + ctx.close() + } + } + }, []) + + useEffect(() => { + if (!audioCtx) return + const filter = audioCtx.createBiquadFilter() + // Load audio track + const track = audioCtx.createMediaElementSource(audio) + + // Create gain node + const gainNode = audioCtx.createGain() + + // Create filter node + + filter.type = "lowpass" + + console.log("Audio Context:", audioCtx) + console.log("Track:", track) + console.log("Gain Node:", gainNode) + console.log("Filter Node:", filter) + + // Connect audio graph + track.connect(gainNode).connect(filter).connect(audioCtx.destination) + + // Set initial volume + gainNode.gain.value = volume + + console.log("Audio Graph Connected.") + + // Clean up event listeners when component unmounts + return () => { + audio.pause() + audio.removeAttribute("src") + audio.load() + } + }, [audioCtx, volume, filterFrequency, audio]) + + const handleVolumeChange = (event: React.ChangeEvent) => { + const newVolume = parseFloat(event.target.value) + setVolume(newVolume) + if (audioElement) { + audioElement.volume = newVolume + } + } + + const handleFilterFrequencyChange = ( + event: React.ChangeEvent, + ) => { + console.log(event.target.value) + const newFilterFrequency = parseFloat(event.target.value) + setFilterFrequency(newFilterFrequency) + filter.frequency.value = filterFrequency + } + + const handlePlayPause = () => { + if (audioElement) { + if (isPlaying) { + audioElement.pause() + } else { + audioElement.play() + } + setIsPlaying((prevState) => !prevState) + } + } + + return ( +
+
+
+
+ + + + + +
+
+
+
+ ) +} + +export default Boombox diff --git a/src/components/audiocontext/WavesurferExample.tsx b/src/components/audiocontext/WavesurferExample.tsx new file mode 100644 index 0000000..93c2629 --- /dev/null +++ b/src/components/audiocontext/WavesurferExample.tsx @@ -0,0 +1,64 @@ +import React, { useEffect, useState, useRef } from "react" +import BlankWaveSurfer from "../WaveSurferPlayer/BlankWaveSurfer" +import { Slider } from "@mantine/core" + +interface AudioEqualizerProps { + audiofile: string +} + +const AudioEqualizer: React.FC = ({ audiofile }) => { + const [audio] = useState(new Audio(audiofile)) + const [audioContext] = useState(new AudioContext()) + const mediaNode = useRef(null) + const lowPassFilter = useRef(null) + const [lowpassFilterFrequency, setLowpassFilterFrequency] = useState(300) + + useEffect(() => { + if (audioContext) { + lowPassFilter.current = audioContext.createBiquadFilter() + lowPassFilter.current.type = "lowpass" + + if (!mediaNode.current) { + mediaNode.current = audioContext.createMediaElementSource(audio) + } + + if (mediaNode.current) { + mediaNode.current.connect(lowPassFilter.current) + lowPassFilter.current.connect(audioContext.destination) + return () => { + mediaNode.current?.disconnect() + } + } + } + }, [audio, audioContext]) + + const handleFaderChange = (e: number) => { + if (lowPassFilter.current) { + lowPassFilter.current.frequency.value = e + } + } + + return ( +
+ handleFaderChange(e)} + /> + +
+ ) +} + +export default AudioEqualizer diff --git a/src/components/audiocontext/audiocontext.tsx b/src/components/audiocontext/audiocontext.tsx new file mode 100644 index 0000000..8a16790 --- /dev/null +++ b/src/components/audiocontext/audiocontext.tsx @@ -0,0 +1,9 @@ +import React, { useState } from "react" +import BlankWaveSurfer from "../WaveSurferPlayer/BlankWaveSurfer" +import treingvbluesberber from "../../assets/music/treingvbluesberber.mp3" + +const AudioContextt: React.FC = () => { + return <> +} + +export default AudioContextt diff --git a/src/components/audiocontext/translated.tsx b/src/components/audiocontext/translated.tsx new file mode 100644 index 0000000..0947762 --- /dev/null +++ b/src/components/audiocontext/translated.tsx @@ -0,0 +1,92 @@ +import React, { useEffect, useState } from "react" +// import WaveSurfer from "wavesurfer.js" + +import treingvbluesberber from "../../assets/music/treingvbluesberber.mp3" + +const AudioComponent = () => { + // Create your own media element + const audio = new Audio() + audio.controls = true + audio.src = treingvbluesberber + + // Create a WaveSurfer instance and pass the media element + // const wavesurfer = WaveSurfer.create({ + // container: document.body, + // waveColor: "rgb(200, 0, 200)", + // progressColor: "rgb(100, 0, 100)", + // media: audio, // <- this is the important part + // }) + + // Optionally, add the audio to the page to see the controls + document.body.appendChild(audio) + + // Create Web Audio context + const audioContext = new AudioContext() + + // Define the equalizer bands + const eqBands = [32, 64, 125, 250, 500, 1000, 2000, 4000, 8000, 16000] + const [filterss, setFilters] = useState( + eqBands.map((bands) => audioContext.createBiquadFilter()), + ) + // Create a biquad filter for each band + const filters = eqBands.map((band) => { + const filter = audioContext.createBiquadFilter() + filter.type = + band <= 32 ? "lowshelf" : band >= 16000 ? "highshelf" : "peaking" + filter.gain.value = Math.random() * 40 - 20 + filter.Q.value = 1 // resonance + filter.frequency.value = band // the cut-off frequency + return filter + }) + + // Connect the audio to the equalizer + audio.addEventListener( + "canplay", + () => { + // Create a MediaElementSourceNode from the audio element + const mediaNode = audioContext.createMediaElementSource(audio) + + // Connect the filters and media node sequentially + const equalizer = filters.reduce((prev, curr) => { + prev.connect(curr) + return curr + }, mediaNode) + + // Connect the filters to the audio output + equalizer.connect(audioContext.destination) + }, + { once: true }, + ) + + const startAudio = () => { + audioContext.resume().then(() => { + audio.play() + // setStarted(true) + }) + } + + return ( +
+ + {eqBands.map((band, index) => ( + { + const newFilters = [...filters] + newFilters[index].gain.value = e.target.value + setFilters(newFilters) + }} + /> + ))} +
+ ) +} + +export default AudioComponent diff --git a/src/pages/audioplayer-page/index.tsx b/src/pages/audioplayer-page/index.tsx index d4d4d7b..ebdc048 100644 --- a/src/pages/audioplayer-page/index.tsx +++ b/src/pages/audioplayer-page/index.tsx @@ -1,9 +1,7 @@ import { Title, Text, Container } from "@mantine/core" -// import treingv from "../../assets/music/treingv.mp3" import treingvbluesberber from "../../assets/music/treingvbluesberber.mp3" -import BlankWaveSurfer from "../../components/WaveSurferPlayer/BlankWaveSurfer" - +import Boombox from "../../components/audiocontext/Boombox" export default function AudioplayerPage() { return ( @@ -13,18 +11,9 @@ export default function AudioplayerPage() { teveel functies. Aangezien ik de web-audio API al beheers kan ik dit component gebruiken om een online/mobile DJ-App te maken. - - - + + {/* */} + {/* */} Wat moet er nog gebeuren? diff --git a/src/pages/patternmaker-page/components/P5WaveFormSketchWrapper.tsx b/src/pages/patternmaker-page/components/P5WaveFormSketchWrapper.tsx index 699a91d..9bf0b40 100644 --- a/src/pages/patternmaker-page/components/P5WaveFormSketchWrapper.tsx +++ b/src/pages/patternmaker-page/components/P5WaveFormSketchWrapper.tsx @@ -1,67 +1,66 @@ -// @ts-ignore -import { ReactP5Wrapper, Sketch, SketchProps } from "@p5-wrapper/react"; -import * as Tone from "tone"; +import { ReactP5Wrapper, Sketch, SketchProps } from "@p5-wrapper/react" +import * as Tone from "tone" type waveformSketchProps = SketchProps & { - color: string; -}; + color: string +} -let meter; -let analyser: Tone.Analyser; -const playing = true; -let waveColor: string; +let meter +let analyser: Tone.Analyser +const playing = true +let waveColor: string const waveformSketch: Sketch = (p: any) => { - meter = new Tone.Meter(); - Tone.Destination.connect(meter); + meter = new Tone.Meter() + Tone.Destination.connect(meter) p.setup = () => { - p.createCanvas(p.windowWidth, p.windowHeight); - p.fill(0); + p.createCanvas(p.windowWidth, p.windowHeight) + p.fill(0) - analyser = new Tone.Analyser("waveform", 512); - Tone.Destination.connect(analyser); - }; + analyser = new Tone.Analyser("waveform", 512) + Tone.Destination.connect(analyser) + } p.updateWithProps = (props: waveformSketchProps) => { if (props.color) { - waveColor = props.color; + waveColor = props.color } - }; + } p.windowResized = () => { - p.resizeCanvas(p.windowWidth, p.windowHeight); - }; + p.resizeCanvas(p.windowWidth, p.windowHeight) + } p.draw = () => { - p.clear(0, 0, 0, 0); - const dim = Math.min(p.width, p.height); - p.strokeWeight(dim * 0.003); - p.stroke(waveColor); - p.noFill(); + p.clear(0, 0, 0, 0) + const dim = Math.min(p.width, p.height) + p.strokeWeight(dim * 0.003) + p.stroke(waveColor) + p.noFill() if (playing) { - const values = analyser.getValue() as Float32Array; + const values = analyser.getValue() as Float32Array - p.beginShape(); + p.beginShape() for (let i = 0; i < values.length; i++) { - const amplitude = values[i] / 2; - const x = p.map(i, 0, values.length - 1, 0, p.width); - const y = p.height / 2; - p.vertex(x, y + amplitude * (p.height / 2)); + const amplitude = values[i] / 2 + const x = p.map(i, 0, values.length - 1, 0, p.width) + const y = p.height / 2 + p.vertex(x, y + amplitude * (p.height / 2)) } - p.endShape(); + p.endShape() } - p.background(0, 0, 0, 0); - }; -}; + p.background(0, 0, 0, 0) + } +} interface P5WaveFormSketchWrapperProps { - colorValue: string; + colorValue: string } const P5WaveFormSketchWrapper: React.FC = ({ colorValue, }) => { - return ; -}; + return +} -export default P5WaveFormSketchWrapper; +export default P5WaveFormSketchWrapper diff --git a/src/pages/patternmaker-page/components/PatternMaker.tsx b/src/pages/patternmaker-page/components/PatternMaker.tsx index 1e8fcb3..de4c26a 100644 --- a/src/pages/patternmaker-page/components/PatternMaker.tsx +++ b/src/pages/patternmaker-page/components/PatternMaker.tsx @@ -1,90 +1,77 @@ -import React, { useState, useEffect } from "react"; -import * as Tone from "tone"; -import { useDispatch, useSelector } from "react-redux"; -import { CurrentPatternUpdater } from "../../../store/patternmaker/actions"; -import { Container, Flex } from "@mantine/core"; -import { selectedPatternSelector } from "../../../store/patternmaker/selectors"; -import { SoundStyle } from "../../../store/patternmaker/types"; -import classes from "./PatternMaker.module.css"; -import { isMobile } from "react-device-detect"; +import React, { useState, useEffect } from "react" +import * as Tone from "tone" +import { useDispatch, useSelector } from "react-redux" +import { CurrentPatternUpdater } from "../../../store/patternmaker/actions" +import { Container, Flex } from "@mantine/core" +import { selectedPatternSelector } from "../../../store/patternmaker/selectors" +import { SoundStyle } from "../../../store/patternmaker/types" +import classes from "./PatternMaker.module.css" +import { isMobile } from "react-device-detect" + interface PatternMakerProps { - output: Tone.OutputNode; - colorValue?: string; + samples: Tone.Sampler | null + colorValue?: string } -let notes: [string, string]; - -const samples = new Tone.Sampler({ - urls: { - A1: "/Loud/cymkik_b3staa.wav", - B1: "/Loud/jaydeesnare_qc9dw5.wav", - C1: "/Metal/cowbell_aihfsc.wav", - D1: "/Metal/hih_gmxx95.wav", - E1: "/Soft/conga_uvdi3n.wav", - F1: "/Soft/snap_mtp0yq.wav", - G1: "/Wood/kick_i1pqe6.wav", - A2: "/Wood/clap_xmxx6f.wav", - }, - baseUrl: - "https://res.cloudinary.com/dqqb0ldgk/video/upload/v1651657689/Drumsounds", -}); +let notes: [string, string] -const PatternMaker: React.FC = ({ output, colorValue }) => { - samples.connect(output); - const dispatch = useDispatch(); - const reduxSequencerPattern = useSelector(selectedPatternSelector); +const PatternMaker: React.FC = ({ samples, colorValue }) => { + const dispatch = useDispatch() + const reduxSequencerPattern = useSelector(selectedPatternSelector) const [currentPattern, updateCurrentPattern] = useState< [boolean[], boolean[]] - >(reduxSequencerPattern.pattern); + >(reduxSequencerPattern.pattern) useEffect(() => { - const loop = new Tone.Sequence( - (time, col) => { - currentPattern.map((rowArray: boolean[], rowIndex: number) => { - if (rowArray[col]) { - samples.triggerAttackRelease(notes[rowIndex], "8n", time); - } - }); - }, - [0, 1, 2, 3, 4, 5, 6, 7], - "8n" - ).start(0); - return () => { - loop.dispose(); - }; - }, [currentPattern]); + if (samples) { + const loop = new Tone.Sequence( + (time, col) => { + currentPattern.map((rowArray: boolean[], rowIndex: number) => { + if (rowArray[col]) { + samples.triggerAttackRelease(notes[rowIndex], "8n", time) + } + }) + }, + [0, 1, 2, 3, 4, 5, 6, 7], + "8n", + ).start(0) + return () => { + loop.dispose() + } + } + }, [currentPattern, samples]) function setPattern({ rowIndex, rowNumber, trigger, }: { - rowIndex: number; - rowNumber: number; - trigger: boolean; + rowIndex: number + rowNumber: number + trigger: boolean }) { - dispatch(CurrentPatternUpdater({ rowNumber, rowIndex, trigger })); + dispatch(CurrentPatternUpdater({ rowNumber, rowIndex, trigger })) } useEffect(() => { - updateCurrentPattern(reduxSequencerPattern.pattern); - }, [reduxSequencerPattern]); + updateCurrentPattern(reduxSequencerPattern.pattern) + }, [reduxSequencerPattern]) switch (reduxSequencerPattern.sound) { case SoundStyle.LOUD: - notes = ["B1", "A1"]; - break; + notes = ["B1", "A1"] + break case SoundStyle.ELECTRONIC: - notes = ["D1", "C1"]; - break; + notes = ["D1", "C1"] + break case SoundStyle.PERCUSSION: - notes = ["F1", "E1"]; - break; + notes = ["F1", "E1"] + break case SoundStyle.NEOSOUL: - notes = ["A2", "G1"]; - break; + notes = ["A2", "G1"] + break default: - notes = ["E2", "G1"]; + notes = ["E2", "G1"] } return ( @@ -114,14 +101,14 @@ const PatternMaker: React.FC = ({ output, colorValue }) => { : undefined, }} onClick={() => { - setPattern({ rowNumber, rowIndex, trigger }); + setPattern({ rowNumber, rowIndex, trigger }) }} /> ))} ))} - ); -}; + ) +} -export default PatternMaker; +export default PatternMaker diff --git a/src/pages/patternmaker-page/index.tsx b/src/pages/patternmaker-page/index.tsx index 7312af9..cf239f7 100644 --- a/src/pages/patternmaker-page/index.tsx +++ b/src/pages/patternmaker-page/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react" +import React, { useEffect, useRef, useState } from "react" import PatternMaker from "./components/PatternMaker" import { selectedPatternSelector, @@ -31,8 +31,8 @@ import DrawerComponent from "../../components/drawer/Drawer" import Uitleg from "./uitleg" const output = new Tone.Volume(-12).toDestination() -const lpFilter = new Tone.Filter(8000, "lowpass", -48).connect(output) -const hpFilter = new Tone.Filter(0, "highpass").connect(lpFilter) +// const lpFilter = new Tone.Filter(8000, "lowpass", -48).connect(output) +// const hpFilter = new Tone.Filter(0, "highpass").connect(lpFilter) const PatternMakerPage: React.FC = () => { const dispatch = useDispatch() @@ -40,6 +40,36 @@ const PatternMakerPage: React.FC = () => { const soundSettings = useSelector(soundSettingsSelector) const [colorValue, setColor] = useState(currentPattern.color) const [titleValue, setTitleValue] = useState(currentPattern.name) + const [samples, setSampler] = useState(null) + + const samplerRef = useRef(null) + + useEffect(() => { + const sampless = new Tone.Sampler({ + urls: { + A1: "/Loud/cymkik_b3staa.wav", + B1: "/Loud/jaydeesnare_qc9dw5.wav", + C1: "/Metal/cowbell_aihfsc.wav", + D1: "/Metal/hih_gmxx95.wav", + E1: "/Soft/conga_uvdi3n.wav", + F1: "/Soft/snap_mtp0yq.wav", + G1: "/Wood/kick_i1pqe6.wav", + A2: "/Wood/clap_xmxx6f.wav", + }, + baseUrl: + "https://res.cloudinary.com/dqqb0ldgk/video/upload/v1651657689/Drumsounds", + }) + setSampler(sampless) + samplerRef.current = sampless // Store the instance in the ref + sampless.connect(output) + return () => { + // Clean up the instance stored in the ref + samplerRef.current?.releaseAll(0) + // Clean up the instance stored in the ref + samplerRef.current?.dispose() + samplerRef.current?.disconnect() + } + }, []) useEffect(() => { setColor(currentPattern.color) @@ -59,8 +89,8 @@ const PatternMakerPage: React.FC = () => { const sendFilters = (value: [number, number]) => { dispatch(SetFilters(value)) - lpFilter.frequency.value = value[1] - hpFilter.frequency.value = value[0] + // lpFilter.frequency.value = value[1] + // hpFilter.frequency.value = value[0] } const sendTempo = (value: number) => { @@ -101,7 +131,7 @@ const PatternMakerPage: React.FC = () => { transform: "translate(0px ,-5px )", }} > - +