1 /* eslint-disable no-script-url */
2 /* eslint-disable jsx-a11y/anchor-is-valid */
3 import axios from 'axios';
4 import React from 'react';
5 import { Component } from 'react';
6 import { Col, Row } from 'react-bootstrap';
7 import YouTube, { Options } from 'react-youtube';
8 import { GiMicrophone, GiDrumKit, GiGuitarHead, GiGuitarBassHead, GiPianoKeys } from 'react-icons/gi';
9 import { IconContext } from 'react-icons';
10 import { db, AudioFiles } from './db';
11
12 interface Result {
13 source_file: string,
14 filename: string
15 }
16
17 interface AudioFile {
18 youtube_video_id: string,
19 results: Result[]
20 }
21
22 type AudioProps = {
23 audioFileId: string
24 }
25
26 type AudioState = {
27 audioFile: AudioFile | null,
28 isPlayerReady: boolean,
29 isPlaying: boolean
30 vocalAudioOn: boolean
31 guitarAudioOn: boolean
32 bassAudioOn: boolean
33 drumsAudioOn: boolean
34 pianoAudioOn: boolean
35 }
36
37 export enum Mode {
38 vocalist, bassist, guitarist, drummer, keyboardist
39 }
40
41 class AudioPlayer extends Component<AudioProps, AudioState> {
42
43 vocalAudio = new Audio();
44 guitarAudio = new Audio();
45 bassAudio = new Audio();
46 drumsAudio = new Audio();
47 pianoAudio = new Audio()
48
49 constructor(props: AudioProps) {
50 super(props);
51 this.state = {
52 audioFile: null,
53 isPlayerReady: false,
54 isPlaying: false,
55 vocalAudioOn: false,
56 guitarAudioOn: false,
57 bassAudioOn: false,
58 drumsAudioOn: false,
59 pianoAudioOn: false,
60 }
61 }
62
63 componentDidMount() {
64 axios.get(`/splitfire/${this.props.audioFileId}`)
65 .then(res => {
66 console.log("Get results", res);
67 const audioFile = res.data.audio_file;
68 this.setState({ audioFile });
69 console.log(this.state);
70 this.downloadAudioFilesIfNeeded();
71 })
72 }
73
74 downloadAudioFilesIfNeeded() {
75 this._prepareAudio(Mode.vocalist);
76 this._prepareAudio(Mode.bassist);
77 this._prepareAudio(Mode.drummer);
78 this._prepareAudio(Mode.guitarist);
79 this._prepareAudio(Mode.keyboardist);
80 }
81
82 async _downloadFile(type: Mode) {
83 console.log('_downloadFile', type);
84 let audioFile: Result | undefined;
85 switch (type) {
86 case Mode.vocalist:
87 audioFile = this.state.audioFile?.results.find(obj => { return obj.filename.startsWith('vocals') });
88 break;
89 case Mode.bassist:
90 audioFile = this.state.audioFile?.results.find(obj => { return obj.filename.startsWith('bass') });
91 break;
92 case Mode.drummer:
93 audioFile = this.state.audioFile?.results.find(obj => { return obj.filename.startsWith('drums') });
94 break;
95 case Mode.guitarist:
96 audioFile = this.state.audioFile?.results.find(obj => { return obj.filename.startsWith('other') });
97 break;
98 case Mode.keyboardist:
99 audioFile = this.state.audioFile?.results.find(obj => { return obj.filename.startsWith('piano') });
100 break;
101 }
102
103 const audioFileId = this.props.audioFileId;
104 console.log("Download url", audioFile?.source_file);
105 axios({
106 url: audioFile?.source_file,
107 method: 'GET',
108 responseType: 'blob',
109 }).then((response) => {
110 const file = new Blob([response.data], { type: 'audio/mp3' });
111 const item: AudioFiles = {
112 audioFileId, type: type, file
113 }
114 db.audioFiles.add(item);
115 console.log('File Downloaded', file);
116 this._setAudioSrc(type, file);
117 }).catch(error => {
118 console.log(error);
119 });
120 }
121
122 async _prepareAudio(type: Mode) {
123 const audioFileId = this.props.audioFileId;
124 db.audioFiles
125 .get({ audioFileId: audioFileId, type: type })
126 .then(record => {
127 if (record?.file === undefined) {
128 this._downloadFile(type);
129 return
130 }
131 this._setAudioSrc(type, record.file)
132 })
133 .catch(onrejected => {
134 console.log("Rejected", onrejected);
135 });
136 }
137
138 _setAudioSrc(type: Mode, file: Blob) {
139 // Get window.URL object
140 var URL = window.URL || window.webkitURL;
141 // Create and revoke ObjectURL
142 var audioFileURL = URL.createObjectURL(file);
143
144 switch (type) {
145 case Mode.vocalist:
146 this.vocalAudio.src = audioFileURL;
147 break;
148 case Mode.bassist:
149 this.bassAudio.src = audioFileURL;
150 break;
151 case Mode.drummer:
152 this.drumsAudio.src = audioFileURL;
153 break;
154 case Mode.guitarist:
155 this.guitarAudio.src = audioFileURL;
156 break;
157 case Mode.keyboardist:
158 this.pianoAudio.src = audioFileURL;
159 break;
160 }
161 }
162
163 playAudio() {
164 this.vocalAudio.play();
165 this.guitarAudio.play();
166 this.bassAudio.play();
167 this.guitarAudio.play();
168 this.drumsAudio.play();
169 }
170
171 pauseAudio() {
172 this.vocalAudio.pause();
173 this.guitarAudio.pause();
174 this.bassAudio.pause();
175 this.guitarAudio.pause();
176 this.drumsAudio.pause();
177 }
178
179 setToggleInstrument(mode: Mode) {
180 switch (mode) {
181 case Mode.vocalist:
182 this.setState({vocalAudioOn: !this.state.vocalAudioOn});
183 this.vocalAudio.volume = this.state.vocalAudioOn ? 1 : 0;
184 break;
185 case Mode.bassist:
186 this.setState({bassAudioOn: !this.state.bassAudioOn});
187 this.bassAudio.volume = this.state.bassAudioOn ? 1 : 0;;
188 break;
189 case Mode.guitarist:
190 this.setState({guitarAudioOn: !this.state.guitarAudioOn});
191 this.guitarAudio.volume = this.state.guitarAudioOn ? 1 : 0;;
192 break;
193 case Mode.keyboardist:
194 this.setState({pianoAudioOn: !this.state.pianoAudioOn});
195 this.pianoAudio.volume = this.state.pianoAudioOn ? 1 : 0;;
196 break;
197 case Mode.drummer:
198 this.setState({drumsAudioOn: !this.state.drumsAudioOn});
199 this.drumsAudio.volume = this.state.drumsAudioOn ? 1 : 0;;
200 break;
201 }
202 }
203
204 render() {
205 const opts: Options = {
206 width: '100%',
207 playerVars: {
208 // https://developers.google.com/youtube/player_parameters
209 autoplay: 0,
210 mute: 1,
211 controls: 0,
212 rel: 0,
213 showinfo: 0
214 },
215 };
216
217 let youtubeContent: any = 'Loading player...';
218 if (this.state.audioFile) {
219 youtubeContent = <YouTube
220 videoId={this.state.audioFile?.youtube_video_id}
221 opts={opts}
222 onReady={this._onReady.bind(this)}
223 onStateChange={this._onStateChange.bind(this)}
224 onPlay={this._onPlay.bind(this)}
225 onPause={this._onPause.bind(this)}
226 />
227 }
228
229 return (
230 <IconContext.Provider value={{ size: "2em", color: "white", className: "global-class-name" }}>
231 <Row className="mb-3 mt-3">
232 <Col>
233 <a href='javascript:void(0)' onClick={() => this.setToggleInstrument(Mode.vocalist)} >
234 <GiMicrophone color={this.state.vocalAudioOn ? `white` : `red`} />
235 </a>
236 </Col>
237 <Col>
238 <a href='javascript:void(0)' onClick={() => this.setToggleInstrument(Mode.drummer)} >
239 <GiDrumKit color={this.state.drumsAudioOn ? `white` : `red`} />
240 </a>
241 </Col>
242 <Col>
243 <a href='javascript:void(0)' onClick={() => this.setToggleInstrument(Mode.bassist)} >
244 <GiGuitarBassHead color={this.state.bassAudioOn ? `white` : `red`} />
245 </a>
246 </Col>
247 <Col>
248 <a href='javascript:void(0)' onClick={() => this.setToggleInstrument(Mode.guitarist)} >
249 <GiGuitarHead color={this.state.guitarAudioOn ? `white` : `red`} />
250 </a>
251 </Col>
252 <Col>
253 <a href='javascript:void(0)' onClick={() => this.setToggleInstrument(Mode.keyboardist)} >
254 <GiPianoKeys color={this.state.pianoAudioOn ? `white` : `red`} />
255 </a>
256 </Col>
257 </Row>
258 <Row>
259 <Col>
260 {youtubeContent}
261 </Col>
262 </Row>
263 </IconContext.Provider>
264 )
265 }
266
267 _onReady(event: any) {
268 console.log('YouTube ready: ', event)
269 }
270
271 _onStateChange(event: any) {
272 console.log('State changed: ', event)
273 }
274
275 _onPlay() {
276 this.playAudio()
277 }
278 _onPause() {
279 this.pauseAudio()
280 }
281 }
282
283 export default AudioPlayer;