From f904bdfc1c335e2e7fe7cdbcbcb311ec8e0b1fa7 Mon Sep 17 00:00:00 2001 From: Nuwan Date: Wed, 31 Jul 2024 11:27:56 +0530 Subject: [PATCH] wip jamtrack player --- jam-ui/package-lock.json | 15 ++ jam-ui/package.json | 1 + .../components/jamtracks/JKCreateCustomMix.js | 252 ++++++++++++++++++ jam-ui/src/components/jamtracks/JKJamTrack.js | 15 +- .../jamtracks/JKJamTrackPlayer copy 2.js | 101 +++++++ .../components/jamtracks/JKJamTrackPlayer.js | 102 ++++--- .../components/jamtracks/JKMyJamTrackMixes.js | 78 ++++++ jam-ui/src/helpers/rest.js | 10 + jam-ui/src/hooks/useJamTrackAudio.js | 60 +++-- 9 files changed, 568 insertions(+), 66 deletions(-) create mode 100644 jam-ui/src/components/jamtracks/JKCreateCustomMix.js create mode 100644 jam-ui/src/components/jamtracks/JKJamTrackPlayer copy 2.js create mode 100644 jam-ui/src/components/jamtracks/JKMyJamTrackMixes.js diff --git a/jam-ui/package-lock.json b/jam-ui/package-lock.json index 0df8cb0e2..62407236b 100644 --- a/jam-ui/package-lock.json +++ b/jam-ui/package-lock.json @@ -3313,6 +3313,21 @@ } } }, + "@fingerprintjs/fingerprintjs": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs/-/fingerprintjs-4.4.3.tgz", + "integrity": "sha512-sm0ZmDp5Oeq8hQTf+bAHKsuuteVAYme/YOY9UPP/GrUBrR5Fzl1P5oOv6F5LvyBrO7qLjU5HQkfU0MmFte/8xA==", + "requires": { + "tslib": "^2.4.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, "@fortawesome/fontawesome-common-types": { "version": "0.2.35", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz", diff --git a/jam-ui/package.json b/jam-ui/package.json index cfa16b7d9..352b6c904 100644 --- a/jam-ui/package.json +++ b/jam-ui/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@farfetch/react-context-responsive": "^1.5.0", + "@fingerprintjs/fingerprintjs": "^4.4.3", "@fortawesome/fontawesome-free": "^5.15.1", "@fortawesome/fontawesome-svg-core": "^1.2.30", "@fortawesome/free-brands-svg-icons": "^5.14.0", diff --git a/jam-ui/src/components/jamtracks/JKCreateCustomMix.js b/jam-ui/src/components/jamtracks/JKCreateCustomMix.js new file mode 100644 index 000000000..c67565a38 --- /dev/null +++ b/jam-ui/src/components/jamtracks/JKCreateCustomMix.js @@ -0,0 +1,252 @@ +import React, { useState, useEffect } from 'react'; +import { Table, Row, Col, Input, Button } from 'reactstrap'; +import JKInstrumentIcon from '../profile/JKInstrumentIcon'; +import Select from 'react-select'; +import { useForm, Controller } from 'react-hook-form'; +import { createMixdown } from '../../helpers/rest'; + +const JKCreateCustomMix = ({ jamTrack }) => { + const [tracks, setTracks] = useState([]); + //const [selectedTracks, setSelectedTracks] = useState([]); + + const TEMPO_OPTIONS = [ + { value: '0', label: 'Original tempo' }, + { value: '-5', label: 'Slower by 5%' }, + { value: '-10', label: 'Slower by 10%' }, + { value: '-15', label: 'Slower by 15%' }, + { value: '-20', label: 'Slower by 20%' }, + { value: '-25', label: 'Slower by 25%' }, + { value: '-30', label: 'Slower by 30%' }, + { value: '-35', label: 'Slower by 35%' }, + { value: '-40', label: 'Slower by 40%' }, + { value: '-45', label: 'Slower by 45%' }, + { value: '-50', label: 'Slower by 50%' }, + { value: '-60', label: 'Slower by 60%' }, + { value: '-70', label: 'Slower by 70%' }, + { value: '-80', label: 'Slower by 80%' }, + { value: '5', label: 'Faster by 5%' }, + { value: '10', label: 'Faster by 10%' }, + { value: '15', label: 'Faster by 15%' }, + { value: '20', label: 'Faster by 20%' }, + { value: '30', label: 'Faster by 30%' }, + { value: '40', label: 'Faster by 40%' }, + { value: '50', label: 'Faster by 50%' } + ]; + + const PITCH_OPTIONS = [ + { value: '0', label: 'Original pitch' }, + { value: '-1', label: 'Down 1 semitone' }, + { value: '-2', label: 'Down 2 semitone' }, + { value: '-3', label: 'Down 3 semitone' }, + { value: '-4', label: 'Down 4 semitone' }, + { value: '-5', label: 'Down 5 semitone' }, + { value: '-6', label: 'Down 6 semitone' }, + { value: '-7', label: 'Down 7 semitone' }, + { value: '-8', label: 'Down 8 semitone' }, + { value: '-9', label: 'Down 9 semitone' }, + { value: '-10', label: 'Down 10 semitone' }, + { value: '-11', label: 'Down 11 semitone' }, + { value: '-12', label: 'Down 12 semitone' }, + { value: '1', label: 'Up 1 semitone' }, + { value: '2', label: 'Up 2 semitone' }, + { value: '3', label: 'Up 3 semitone' }, + { value: '4', label: 'Up 4 semitone' }, + { value: '5', label: 'Up 5 semitone' }, + { value: '6', label: 'Up 6 semitone' }, + { value: '7', label: 'Up 7 semitone' }, + { value: '8', label: 'Up 8 semitone' }, + { value: '9', label: 'Up 9 semitone' }, + { value: '10', label: 'Up 10 semitone' }, + { value: '11', label: 'Up 11 semitone' }, + { value: '12', label: 'Up 12 semitone' } + ]; + + const { + control, + handleSubmit, + formState: { errors }, + setValue, + getValues + } = useForm({ + defaultValues: { + mixName: '', + tempo: { + value: '0', + label: 'Original tempo' + }, + pitch: { + value: '0', + label: 'Original pitch' + }, + mixdownTracks: [] + } + }); + const onSubmit = data => { + console.log('data', data); + const _tracks = []; + let countIn = false; + const selectedTracks = getValues('mixdownTracks'); + tracks.forEach(track => { + const muted = selectedTracks.includes(track.id); + if (track.id === 'count-in') { + if (countIn === false) { + countIn = !muted; + } + } else { + _tracks.push({ + id: track.id, + mute: selectedTracks.includes(track.id) + }); + } + }); + + setValue('mixdownTracks', _tracks); + + const mixData = { + jamTrackID: jamTrack.id, + name: data.mixName, + settings: { speed: data.tempo.value, pitch: data.pitch.value, 'count-in': countIn, tracks: _tracks } + }; + + console.log('mixData', mixData); + + createMixdown(mixData) + .then(response => { + console.log('mixdown created', response); + //TODO: add this mixdown to global state of jamtrack mixdowns + }) + .catch(error => { + console.error('mixdown create error', error); + }); + }; + + const toggleTrack = e => { + const trackId = e.target.value; + const selectedTracks = getValues('mixdownTracks'); + if (selectedTracks.includes(trackId)) { + //setSelectedTracks(selectedTracks.filter(track => track !== trackId)); + setValue('mixdownTracks', selectedTracks.filter(track => track !== trackId)); + } else { + //setSelectedTracks([...selectedTracks, trackId]); + setValue('mixdownTracks', [...selectedTracks, trackId]); + } + }; + + useEffect(() => { + if (jamTrack) { + setTracks(jamTrack.tracks.filter(track => track.track_type === 'Track' || track.track_type === 'Click')); + } + }, [jamTrack]); + + const trackName = track => { + if (track.track_type === 'Track' || track.track_type === 'Click') { + if (track.track_type === 'Click') { + return 'Clicktrack'; + } else if (track.instrument) { + const instrumentDescription = track.instrument.description; + let part = ''; + if (track.part && track.part !== instrumentDescription) { + part = `(${track.part})`; + } + return `${instrumentDescription} ${part}`; + } + } + }; + + return ( + <> +

+ Mute any tracks you like. Adjust the pitch or tempo of playback. Then give your mix a descriptive name, and + click the Create Mix button. It will take few minutes for us to create your custom mix. +

+ +
+ + + + + + + + + + + {tracks && + tracks.map((track, index) => ( + + + + + ))} + +
Tracks {tracks.length > 0 && <>({tracks.length})}Mute
+ + {trackName(track)} + + +
+ } + /> + {errors.mixdownTracks && ( +
+ {errors.mixdownTracks.message} +
+ )} + +
+ + + Tempo + + } + /> + + + + Mix Name + + } + /> + {errors.mixName && ( +
+ {errors.mixName.message} +
+ )} + +
+ + + + + +
+ + ); +}; + +export default JKCreateCustomMix; diff --git a/jam-ui/src/components/jamtracks/JKJamTrack.js b/jam-ui/src/components/jamtracks/JKJamTrack.js index e0d001dda..6acd83bdb 100644 --- a/jam-ui/src/components/jamtracks/JKJamTrack.js +++ b/jam-ui/src/components/jamtracks/JKJamTrack.js @@ -6,6 +6,8 @@ import { Card, CardBody, Row, Col, Progress } from 'reactstrap'; import FalconCardHeader from '../common/FalconCardHeader'; import { getJamTrack, getUserDetail, postUserEvent, userOpenedJamTrackWebPlayer } from '../../helpers/rest'; import JKJamTrackPlayer from './JKJamTrackPlayer'; +import JKMyJamTrackMixes from './JKMyJamTrackMixes'; +import JKCreateCustomMix from './JKCreateCustomMix'; import { useAuth } from '../../context/UserAuth'; const JKJamTrack = () => { @@ -23,6 +25,7 @@ const JKJamTrack = () => { setLoading(true); const resp = await getJamTrack({ id }); const data = await resp.json(); + console.log('jam track 123', data); setJamTrack(data); } catch (error) { console.log('Error when fetching jam track', error); @@ -58,26 +61,24 @@ const JKJamTrack = () => { fetchJamTrack(); }, [id]); - - return ( - - {jamTrack && } - + {jamTrack && } - + {jamTrack && } - + + { jamTrack && } + diff --git a/jam-ui/src/components/jamtracks/JKJamTrackPlayer copy 2.js b/jam-ui/src/components/jamtracks/JKJamTrackPlayer copy 2.js new file mode 100644 index 000000000..6843d5f66 --- /dev/null +++ b/jam-ui/src/components/jamtracks/JKJamTrackPlayer copy 2.js @@ -0,0 +1,101 @@ +import React, { useState, useEffect, useMemo } from 'react'; +import Select from 'react-select'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Row, Col } from 'reactstrap'; +import PropTypes from 'prop-types'; +import { markMixdownActive } from '../../helpers/rest'; +import useJamTrackAudio from '../../hooks/useJamTrackAudio'; + +const JKJamTrackPlayer = ({ jamTrack }) => { + const [mixes, setMixes] = useState([]); + const [options, setOptions] = useState([]); + const [selectedMix, setSelectedMix] = useState(null); + const { audioUrls, loadJamTrack } = useJamTrackAudio(jamTrack); + + const handleChange = selectedOption => { + const mix = mixes.find(mix => mix.value === selectedOption.value); + setSelectedMix(mix); + }; + + useEffect(() => { + if (jamTrack) { + console.log('_JamTrack_ jamTrack', jamTrack); + const _opts = jamTrack.mixdowns.map(mix => ({ value: mix.id, label: mix.name })); + _opts.unshift({ value: 'original', label: 'Original' }); + setOptions(_opts); + + //set the default mix to the original + const activeMix = jamTrack.mixdowns.find(mix => mix.id === jamTrack.last_mixdown_id) + + console.log('_JamTrack_ activeMix', activeMix); + + setSelectedMix(activeMix); + } + }, [jamTrack]); + + const activateMasterTrack = async () => { + console.log('playing original'); + await markMixdownActive({ id: jamTrack.id, mixdown_id: null }); + await loadJamTrack(); + }; + + const activateCustomMix = async () => { + console.log('playing mix', selectedMix.value); + try { + await markMixdownActive({ id: jamTrack.id, mixdown_id: selectedMix.value }); + await loadJamTrack(); + }catch(error){ + console.log('Error when activating custom mix', error); + } + + }; + + useEffect(() => { + if (!selectedMix) { + return; + } + + console.log('_JamTrack_ selectedMix', selectedMix); + + if (selectedMix.value === 'original') { + //console.log('_JAMTRACK_ activating master track'); + activateMasterTrack().then(() => { + //TODO: commiunicate with the client back end. Following is copied from the Rails front end + //SessionActions.mixdownActive({id:null}) + }); + } else { + //console.log('_JAMTRACK_ activating custom mix:', selectedMix); + activateCustomMix().then(() => { + //TODO: commiunicate with the client back end. Following is copied from the Rails front end + //context.jamClient.JamTrackStopPlay(); + //SessionActions.mixdownActive(mixdown) + }); + } + }, [selectedMix]); + + return ( + <> + - +