-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAudioBufferSource.tsx
106 lines (95 loc) · 2.97 KB
/
AudioBufferSource.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import React, { useCallback, useRef } from "react";
import { NodeProps } from "react-flow-renderer";
import { useNode } from "context/NodeContext";
import Node from "components/Node";
import { AudioBufferSourceNode } from "utils/audioContext";
function AudioBufferSource({ data, id, selected, type }: NodeProps) {
const { loop = true, onChange } = data;
const activeBufferSource = useRef<AudioBufferSourceNode>();
// TODO buffer source -> gain and swap buffer
// AudioNode
const node = useNode(id, context => context.createGain());
const linkBufferSource = useCallback(
(bufferSource: AudioBufferSourceNode) => {
// cleanup previous
activeBufferSource.current?.disconnect();
activeBufferSource.current = bufferSource;
// start new
activeBufferSource.current.connect(node);
},
[node]
);
const start = useCallback(() => {
if (!activeBufferSource.current) {
return;
}
const bufferSource = node.context.createBufferSource();
bufferSource.buffer = activeBufferSource.current.buffer;
bufferSource.loop = loop;
linkBufferSource(bufferSource);
activeBufferSource.current.start();
}, [node, loop, linkBufferSource]);
const stop = useCallback(() => {
try {
activeBufferSource.current?.stop();
} catch {}
}, []);
const handleNewFile = useCallback(
async (file: File) => {
const bufferSource = node.context.createBufferSource();
bufferSource.buffer = await node.context.decodeAudioData(await file.arrayBuffer());
bufferSource.loop = loop;
linkBufferSource(bufferSource);
},
[node, loop, linkBufferSource]
);
const handleChange = useCallback(
e => {
e.preventDefault();
handleNewFile(e.target.files[0]);
},
[handleNewFile]
);
const handleDragOver = useCallback(e => void e.preventDefault(), []);
const handleDrop = useCallback(
async e => {
e.preventDefault();
const file: File = [...e.dataTransfer.items]
.filter((item: DataTransferItem) => item.kind === "file")[0]
.getAsFile();
handleNewFile(file);
},
[handleNewFile]
);
return (
<Node
id={id}
outputs={["output"]}
title="Buffer Source"
type={type}
onDragOver={handleDragOver}
onDrop={handleDrop}
>
<div className="customNode_editor nodrag">
<div className="customNode_item">
<button onClick={start}>Play</button>
<button onClick={stop}>Stop</button>
</div>
{selected && (
<>
<div className="customNode_item">
<input onChange={handleChange} type="file" />
</div>
<div className="customNode_item">
<label>
<input checked={loop} onChange={() => onChange({ loop: !loop })} title="Loop" type="checkbox" />
Loop
</label>
</div>
</>
)}
</div>
</Node>
);
}
export default React.memo(AudioBufferSource);