Compare commits
2 Commits
main
...
sound-expe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0db8d49618 | ||
|
|
4923fc72b2 |
@@ -1,12 +1,12 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { Slider, View, IconButton, Icon } from 'native-base';
|
import { Slider, View, IconButton, Icon } from 'native-base';
|
||||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||||
import { Audio } from 'expo-av';
|
// import { Audio } from 'expo-av';
|
||||||
import { VolumeHigh, VolumeSlash } from 'iconsax-react-native';
|
import { VolumeHigh, VolumeSlash } from 'iconsax-react-native';
|
||||||
import { Translate } from '../i18n/i18n';
|
import { Translate } from '../i18n/i18n';
|
||||||
|
|
||||||
export const MetronomeControls = ({ paused = false, bpm }: { paused?: boolean; bpm: number }) => {
|
export const MetronomeControls = ({ paused = false, bpm }: { paused?: boolean; bpm: number }) => {
|
||||||
const audio = useRef<Audio.Sound | null>(null);
|
const audio = useRef<null>(null);
|
||||||
const [enabled, setEnabled] = useState<boolean>(false);
|
const [enabled, setEnabled] = useState<boolean>(false);
|
||||||
const volume = useRef<number>(50);
|
const volume = useRef<number>(50);
|
||||||
|
|
||||||
@@ -15,12 +15,12 @@ export const MetronomeControls = ({ paused = false, bpm }: { paused?: boolean; b
|
|||||||
return;
|
return;
|
||||||
} else if (!audio.current) {
|
} else if (!audio.current) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
Audio.Sound.createAsync(require('../assets/metronome.mp3')).then((a) => {
|
// Audio.Sound.createAsync(require('../assets/metronome.mp3')).then((a) => {
|
||||||
audio.current = a.sound;
|
// audio.current = a.sound;
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
audio.current?.unloadAsync();
|
// audio.current?.unloadAsync();
|
||||||
};
|
};
|
||||||
}, [enabled]);
|
}, [enabled]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -28,12 +28,12 @@ export const MetronomeControls = ({ paused = false, bpm }: { paused?: boolean; b
|
|||||||
const int = setInterval(() => {
|
const int = setInterval(() => {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
if (!audio.current) return;
|
if (!audio.current) return;
|
||||||
audio.current?.playAsync();
|
// audio.current?.playAsync();
|
||||||
}, 60000 / bpm);
|
}, 60000 / bpm);
|
||||||
return () => clearInterval(int);
|
return () => clearInterval(int);
|
||||||
}, [bpm, paused]);
|
}, [bpm, paused]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
audio.current?.setVolumeAsync(volume.current / 100);
|
// audio.current?.setVolumeAsync(volume.current / 100);
|
||||||
}, [volume.current]);
|
}, [volume.current]);
|
||||||
return (
|
return (
|
||||||
<View flex={1}>
|
<View flex={1}>
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ import { useQuery } from '../../Queries';
|
|||||||
import Animated, { useSharedValue, withTiming, Easing } from 'react-native-reanimated';
|
import Animated, { useSharedValue, withTiming, Easing } from 'react-native-reanimated';
|
||||||
import { CursorInfoItem } from '../../models/SongCursorInfos';
|
import { CursorInfoItem } from '../../models/SongCursorInfos';
|
||||||
import { PianoNotes } from '../../state/SoundPlayerSlice';
|
import { PianoNotes } from '../../state/SoundPlayerSlice';
|
||||||
import { Audio } from 'expo-av';
|
// import { Audio } from 'expo-av';
|
||||||
import { SvgContainer } from './SvgContainer';
|
import { SvgContainer } from './SvgContainer';
|
||||||
import LoadingComponent from '../Loading';
|
import LoadingComponent from '../Loading';
|
||||||
|
import Sound from 'react-native-sound';
|
||||||
|
|
||||||
|
Sound.setCategory('Playback');
|
||||||
|
|
||||||
// note we are also using timestamp in a context
|
// note we are also using timestamp in a context
|
||||||
export type ParitionMagicProps = {
|
export type ParitionMagicProps = {
|
||||||
@@ -51,7 +54,7 @@ const PartitionMagic = ({
|
|||||||
const [endPartitionReached, setEndPartitionReached] = React.useState(false);
|
const [endPartitionReached, setEndPartitionReached] = React.useState(false);
|
||||||
const [isPartitionSvgLoaded, setIsPartitionSvgLoaded] = React.useState(false);
|
const [isPartitionSvgLoaded, setIsPartitionSvgLoaded] = React.useState(false);
|
||||||
const partitionOffset = useSharedValue(0);
|
const partitionOffset = useSharedValue(0);
|
||||||
const pianoSounds = React.useRef<Record<string, Audio.Sound> | null>(null);
|
const pianoSounds = React.useRef<Record<string, Sound> | null>(null);
|
||||||
const cursorPaddingVertical = 10;
|
const cursorPaddingVertical = 10;
|
||||||
const cursorPaddingHorizontal = 3;
|
const cursorPaddingHorizontal = 3;
|
||||||
|
|
||||||
@@ -72,21 +75,40 @@ const PartitionMagic = ({
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!pianoSounds.current) {
|
if (!pianoSounds.current) {
|
||||||
Promise.all(
|
Promise.all(
|
||||||
Object.entries(PianoNotes).map(([midiNumber, noteResource]) =>
|
Object.entries(PianoNotes).map(([midiNumber, noteResource]) => {
|
||||||
Audio.Sound.createAsync(noteResource, {
|
// Audio.Sound.createAsync(noteResource, {
|
||||||
volume: 1,
|
// volume: 1,
|
||||||
progressUpdateIntervalMillis: 100,
|
// progressUpdateIntervalMillis: 100,
|
||||||
}).then((sound) => [midiNumber, sound.sound] as const)
|
// }).then((sound) => [midiNumber, sound.sound] as const)
|
||||||
)
|
return new Promise((resolve, reject) => {
|
||||||
|
const sound = new Sound(noteResource, Sound.MAIN_BUNDLE, (error: any) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve([midiNumber, sound] as const);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
).then((res) => {
|
).then((res) => {
|
||||||
pianoSounds.current = res.reduce(
|
// pianoSounds.current = res.reduce(
|
||||||
(prev, curr) => ({ ...prev, [curr[0]]: curr[1] }),
|
// (prev, curr) => ({ ...prev, [curr[0]]: curr[1] }),
|
||||||
{}
|
// {}
|
||||||
);
|
// );
|
||||||
|
pianoSounds.current = {};
|
||||||
|
(res as [string, Sound][]).forEach((curr) => {
|
||||||
|
pianoSounds.current![curr[0]] = curr[1];
|
||||||
|
});
|
||||||
console.log('sound loaded');
|
console.log('sound loaded');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, []);
|
}, [
|
||||||
|
() => {
|
||||||
|
pianoSounds?.current?.forEach((sound) => {
|
||||||
|
sound.release();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
]);
|
||||||
const partitionDims = React.useMemo<[number, number]>(() => {
|
const partitionDims = React.useMemo<[number, number]>(() => {
|
||||||
return [data?.pageWidth ?? 0, data?.pageHeight ?? 1];
|
return [data?.pageWidth ?? 0, data?.pageHeight ?? 1];
|
||||||
}, [data]);
|
}, [data]);
|
||||||
@@ -122,12 +144,16 @@ const PartitionMagic = ({
|
|||||||
cursor.notes.forEach(({ note, duration }) => {
|
cursor.notes.forEach(({ note, duration }) => {
|
||||||
try {
|
try {
|
||||||
const sound = pianoSounds.current![note]!;
|
const sound = pianoSounds.current![note]!;
|
||||||
sound.playAsync().catch(console.error);
|
sound.play((success) => {
|
||||||
|
if (!success) {
|
||||||
|
console.log('Sound did not play');
|
||||||
|
}
|
||||||
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
sound.stopAsync();
|
sound.stop();
|
||||||
}, duration - 10);
|
}, duration - 10);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log('Error key: ', note, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
"react-native-reanimated": "~3.3.0",
|
"react-native-reanimated": "~3.3.0",
|
||||||
"react-native-safe-area-context": "4.6.3",
|
"react-native-safe-area-context": "4.6.3",
|
||||||
"react-native-screens": "~3.22.0",
|
"react-native-screens": "~3.22.0",
|
||||||
|
"react-native-sound": "^0.11.2",
|
||||||
"react-native-super-grid": "^5.0.0",
|
"react-native-super-grid": "^5.0.0",
|
||||||
"react-native-svg": "14.0.0",
|
"react-native-svg": "14.0.0",
|
||||||
"react-native-tab-view": "^3.5.2",
|
"react-native-tab-view": "^3.5.2",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { Audio } from 'expo-av';
|
// import { Audio } from 'expo-av';
|
||||||
|
|
||||||
type MidiNumber = number;
|
type MidiNumber = number;
|
||||||
|
|
||||||
@@ -7,97 +7,97 @@ type MidiNumber = number;
|
|||||||
// Deserve an extra credit for doing this by hand
|
// Deserve an extra credit for doing this by hand
|
||||||
// The value is the value returned by `required`, needed by Expo to load/play the sound
|
// The value is the value returned by `required`, needed by Expo to load/play the sound
|
||||||
export const PianoNotes = {
|
export const PianoNotes = {
|
||||||
33: require('../assets/piano/a0.mp3'),
|
33: 'a0.mp3',
|
||||||
45: require('../assets/piano/a1.mp3'),
|
45: 'a1.mp3',
|
||||||
57: require('../assets/piano/a2.mp3'),
|
57: 'a2.mp3',
|
||||||
69: require('../assets/piano/a3.mp3'),
|
69: 'a3.mp3',
|
||||||
81: require('../assets/piano/a4.mp3'),
|
81: 'a4.mp3',
|
||||||
93: require('../assets/piano/a5.mp3'),
|
93: 'a5.mp3',
|
||||||
105: require('../assets/piano/a6.mp3'),
|
105: 'a6.mp3',
|
||||||
117: require('../assets/piano/a7.mp3'),
|
117: 'a7.mp3',
|
||||||
44: require('../assets/piano/ab1.mp3'),
|
44: 'ab1.mp3',
|
||||||
56: require('../assets/piano/ab2.mp3'),
|
56: 'ab2.mp3',
|
||||||
68: require('../assets/piano/ab3.mp3'),
|
68: 'ab3.mp3',
|
||||||
80: require('../assets/piano/ab4.mp3'),
|
80: 'ab4.mp3',
|
||||||
92: require('../assets/piano/ab5.mp3'),
|
92: 'ab5.mp3',
|
||||||
104: require('../assets/piano/ab6.mp3'),
|
104: 'ab6.mp3',
|
||||||
116: require('../assets/piano/ab7.mp3'),
|
116: 'ab7.mp3',
|
||||||
35: require('../assets/piano/b0.mp3'),
|
35: 'b0.mp3',
|
||||||
47: require('../assets/piano/b1.mp3'),
|
47: 'b1.mp3',
|
||||||
59: require('../assets/piano/b2.mp3'),
|
59: 'b2.mp3',
|
||||||
71: require('../assets/piano/b3.mp3'),
|
71: 'b3.mp3',
|
||||||
83: require('../assets/piano/b4.mp3'),
|
83: 'b4.mp3',
|
||||||
95: require('../assets/piano/b5.mp3'),
|
95: 'b5.mp3',
|
||||||
107: require('../assets/piano/b6.mp3'),
|
107: 'b6.mp3',
|
||||||
119: require('../assets/piano/b7.mp3'),
|
119: 'b7.mp3',
|
||||||
34: require('../assets/piano/bb0.mp3'),
|
34: 'bb0.mp3',
|
||||||
46: require('../assets/piano/bb1.mp3'),
|
46: 'bb1.mp3',
|
||||||
58: require('../assets/piano/bb2.mp3'),
|
58: 'bb2.mp3',
|
||||||
70: require('../assets/piano/bb3.mp3'),
|
70: 'bb3.mp3',
|
||||||
82: require('../assets/piano/bb4.mp3'),
|
82: 'bb4.mp3',
|
||||||
94: require('../assets/piano/bb5.mp3'),
|
94: 'bb5.mp3',
|
||||||
106: require('../assets/piano/bb6.mp3'),
|
106: 'bb6.mp3',
|
||||||
118: require('../assets/piano/bb7.mp3'),
|
118: 'bb7.mp3',
|
||||||
36: require('../assets/piano/c1.mp3'),
|
36: 'c1.mp3',
|
||||||
48: require('../assets/piano/c2.mp3'),
|
48: 'c2.mp3',
|
||||||
60: require('../assets/piano/c3.mp3'),
|
60: 'c3.mp3',
|
||||||
72: require('../assets/piano/c4.mp3'),
|
72: 'c4.mp3',
|
||||||
84: require('../assets/piano/c5.mp3'),
|
84: 'c5.mp3',
|
||||||
96: require('../assets/piano/c6.mp3'),
|
96: 'c6.mp3',
|
||||||
108: require('../assets/piano/c7.mp3'),
|
108: 'c7.mp3',
|
||||||
120: require('../assets/piano/c8.mp3'),
|
120: 'c8.mp3',
|
||||||
38: require('../assets/piano/d1.mp3'),
|
38: 'd1.mp3',
|
||||||
50: require('../assets/piano/d2.mp3'),
|
50: 'd2.mp3',
|
||||||
62: require('../assets/piano/d3.mp3'),
|
62: 'd3.mp3',
|
||||||
74: require('../assets/piano/d4.mp3'),
|
74: 'd4.mp3',
|
||||||
86: require('../assets/piano/d5.mp3'),
|
86: 'd5.mp3',
|
||||||
98: require('../assets/piano/d6.mp3'),
|
98: 'd6.mp3',
|
||||||
110: require('../assets/piano/d7.mp3'),
|
110: 'd7.mp3',
|
||||||
37: require('../assets/piano/db1.mp3'),
|
37: 'db1.mp3',
|
||||||
49: require('../assets/piano/db2.mp3'),
|
49: 'db2.mp3',
|
||||||
61: require('../assets/piano/db3.mp3'),
|
61: 'db3.mp3',
|
||||||
73: require('../assets/piano/db4.mp3'),
|
73: 'db4.mp3',
|
||||||
85: require('../assets/piano/db5.mp3'),
|
85: 'db5.mp3',
|
||||||
97: require('../assets/piano/db6.mp3'),
|
97: 'db6.mp3',
|
||||||
109: require('../assets/piano/db7.mp3'),
|
109: 'db7.mp3',
|
||||||
40: require('../assets/piano/e1.mp3'),
|
40: 'e1.mp3',
|
||||||
52: require('../assets/piano/e2.mp3'),
|
52: 'e2.mp3',
|
||||||
64: require('../assets/piano/e3.mp3'),
|
64: 'e3.mp3',
|
||||||
76: require('../assets/piano/e4.mp3'),
|
76: 'e4.mp3',
|
||||||
88: require('../assets/piano/e5.mp3'),
|
88: 'e5.mp3',
|
||||||
100: require('../assets/piano/e6.mp3'),
|
100: 'e6.mp3',
|
||||||
112: require('../assets/piano/e7.mp3'),
|
112: 'e7.mp3',
|
||||||
39: require('../assets/piano/eb1.mp3'),
|
39: 'eb1.mp3',
|
||||||
51: require('../assets/piano/eb2.mp3'),
|
51: 'eb2.mp3',
|
||||||
63: require('../assets/piano/eb3.mp3'),
|
63: 'eb3.mp3',
|
||||||
75: require('../assets/piano/eb4.mp3'),
|
75: 'eb4.mp3',
|
||||||
87: require('../assets/piano/eb5.mp3'),
|
87: 'eb5.mp3',
|
||||||
99: require('../assets/piano/eb6.mp3'),
|
99: 'eb6.mp3',
|
||||||
111: require('../assets/piano/eb7.mp3'),
|
111: 'eb7.mp3',
|
||||||
41: require('../assets/piano/f1.mp3'),
|
41: 'f1.mp3',
|
||||||
53: require('../assets/piano/f2.mp3'),
|
53: 'f2.mp3',
|
||||||
65: require('../assets/piano/f3.mp3'),
|
65: 'f3.mp3',
|
||||||
77: require('../assets/piano/f4.mp3'),
|
77: 'f4.mp3',
|
||||||
89: require('../assets/piano/f5.mp3'),
|
89: 'f5.mp3',
|
||||||
101: require('../assets/piano/f6.mp3'),
|
101: 'f6.mp3',
|
||||||
113: require('../assets/piano/f7.mp3'),
|
113: 'f7.mp3',
|
||||||
43: require('../assets/piano/g1.mp3'),
|
43: 'g1.mp3',
|
||||||
55: require('../assets/piano/g2.mp3'),
|
55: 'g2.mp3',
|
||||||
67: require('../assets/piano/g3.mp3'),
|
67: 'g3.mp3',
|
||||||
79: require('../assets/piano/g4.mp3'),
|
79: 'g4.mp3',
|
||||||
91: require('../assets/piano/g5.mp3'),
|
91: 'g5.mp3',
|
||||||
103: require('../assets/piano/g6.mp3'),
|
103: 'g6.mp3',
|
||||||
115: require('../assets/piano/g7.mp3'),
|
115: 'g7.mp3',
|
||||||
42: require('../assets/piano/gb1.mp3'),
|
42: 'gb1.mp3',
|
||||||
54: require('../assets/piano/gb2.mp3'),
|
54: 'gb2.mp3',
|
||||||
66: require('../assets/piano/gb3.mp3'),
|
66: 'gb3.mp3',
|
||||||
78: require('../assets/piano/gb4.mp3'),
|
78: 'gb4.mp3',
|
||||||
90: require('../assets/piano/gb5.mp3'),
|
90: 'gb5.mp3',
|
||||||
102: require('../assets/piano/gb6.mp3'),
|
102: 'gb6.mp3',
|
||||||
114: require('../assets/piano/gb7.mp3'),
|
114: 'gb7.mp3',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type Sounds = Record<MidiNumber, Audio.Sound>;
|
export type Sounds = Record<MidiNumber, string>;
|
||||||
|
|
||||||
export const soundPlayerSlice = createSlice({
|
export const soundPlayerSlice = createSlice({
|
||||||
name: 'soundPlayer',
|
name: 'soundPlayer',
|
||||||
@@ -107,11 +107,10 @@ export const soundPlayerSlice = createSlice({
|
|||||||
reducers: {
|
reducers: {
|
||||||
setSounds: (state, action: PayloadAction<Sounds>) => {
|
setSounds: (state, action: PayloadAction<Sounds>) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
//@ts-expect-error
|
|
||||||
state.sounds = action.payload;
|
state.sounds = action.payload;
|
||||||
},
|
},
|
||||||
unsetSounds: (state) => {
|
unsetSounds: (state) => {
|
||||||
Object.entries(state.sounds ?? {}).map((sound) => sound[1].unloadAsync());
|
// Object.entries(state.sounds ?? {}).map((sound) => sound[1].unloadAsync());
|
||||||
state.sounds = undefined;
|
state.sounds = undefined;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9948,6 +9948,11 @@ react-native-screens@~3.22.0:
|
|||||||
react-freeze "^1.0.0"
|
react-freeze "^1.0.0"
|
||||||
warn-once "^0.1.0"
|
warn-once "^0.1.0"
|
||||||
|
|
||||||
|
react-native-sound@^0.11.2:
|
||||||
|
version "0.11.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-native-sound/-/react-native-sound-0.11.2.tgz#e542dc5b9e16ab4b3ac7e6eaddb1fc8d98da9038"
|
||||||
|
integrity sha512-LmGc8lgOK3qecYMVQpyHvww/C+wgT6sWeMpVbOe4NCRGC2yKd4fo4U0KBUo9PO7AqKESO3I/2GZg1/C0+bwiiA==
|
||||||
|
|
||||||
react-native-super-grid@^5.0.0:
|
react-native-super-grid@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-super-grid/-/react-native-super-grid-5.0.0.tgz#0cf9cfb86864198a1e6925d26496bd005b319e3e"
|
resolved "https://registry.yarnpkg.com/react-native-super-grid/-/react-native-super-grid-5.0.0.tgz#0cf9cfb86864198a1e6925d26496bd005b319e3e"
|
||||||
|
|||||||
Reference in New Issue
Block a user