diff --git a/front/App.tsx b/front/App.tsx index 49db9e3..e3b7ea4 100644 --- a/front/App.tsx +++ b/front/App.tsx @@ -8,6 +8,7 @@ import * as SplashScreen from 'expo-splash-screen'; import { PersistGate } from "redux-persist/integration/react"; import LanguageGate from "./i18n/LanguageGate"; import ThemeProvider, { ColorSchemeProvider } from './Theme'; +import 'react-native-url-polyfill/auto'; const queryClient = new QueryClient({ defaultOptions: { diff --git a/front/components/PartitionView.tsx b/front/components/PartitionView.tsx index 0a08a4b..d9ebd63 100644 --- a/front/components/PartitionView.tsx +++ b/front/components/PartitionView.tsx @@ -5,6 +5,7 @@ import { CursorType, Fraction, OpenSheetMusicDisplay as OSMD, IOSMDOptions, Note import useColorScheme from '../hooks/colorScheme'; import { useWindowDimensions } from 'react-native'; import SoundFont from 'soundfont-player'; +import { AudioContext } from 'standardized-audio-context'; type PartitionViewProps = { // The Buffer of the MusicXML file retreived from the API @@ -18,7 +19,6 @@ type PartitionViewProps = { const PartitionView = (props: PartitionViewProps) => { const [osmd, setOsmd] = useState(); const [soundPlayer, setSoundPlayer] = useState(); - const AudioContext = window.AudioContext || window.webkitAudioContext || false; const audioContext = new AudioContext(); const [wholeNoteLength, setWholeNoteLength] = useState(0); // Length of Whole note, in ms (?) const colorScheme = useColorScheme(); @@ -63,11 +63,11 @@ const PartitionView = (props: PartitionViewProps) => { // console.log('Expecting midi ' + midiNumber); let duration = getActualNoteLength(note); const gain = note.ParentVoiceEntry.ParentVoice.Volume; - soundPlayer!.play(midiNumber, audioContext.currentTime, { duration, gain }) + soundPlayer!.play(midiNumber.toString(), audioContext.currentTime, { duration, gain }) }); } const getShortedNoteUnderCursor = () => { - return osmd.cursor.NotesUnderCursor().sort((n1, n2) => n1.Length.CompareTo(n2.Length)).at(0); + return osmd!.cursor.NotesUnderCursor().sort((n1, n2) => n1.Length.CompareTo(n2.Length)).at(0); } useEffect(() => { @@ -125,7 +125,7 @@ const PartitionView = (props: PartitionViewProps) => { // Shamelessly stolen from https://github.com/jimutt/osmd-audio-player/blob/ec205a6e46ee50002c1fa8f5999389447bba7bbf/src/PlaybackEngine.ts#LL223C7-L224C1 playNotesUnderCursor(); currentCursorPosition = osmd.cursor.cursorElement.offsetLeft; - document.getElementById(OSMD_DIV_ID).scrollBy(currentCursorPosition - previousCursorPosition, 0) + document.getElementById(OSMD_DIV_ID)?.scrollBy(currentCursorPosition - previousCursorPosition, 0) shortestNote = getShortedNoteUnderCursor(); } } diff --git a/front/package.json b/front/package.json index 08a90f9..243fa81 100644 --- a/front/package.json +++ b/front/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@expo/vector-icons": "^13.0.0", + "@motiz88/react-native-midi": "^0.0.5", "@react-native-async-storage/async-storage": "~1.17.3", "@react-navigation/native": "^6.0.11", "@react-navigation/native-stack": "^6.7.0", @@ -30,6 +31,7 @@ "expo": "^47.0.8", "expo-asset": "~8.7.0", "expo-dev-client": "~2.0.1", + "expo-linking": "~3.3.1", "expo-screen-orientation": "~5.0.1", "expo-secure-store": "~12.0.0", "expo-splash-screen": "~0.17.5", @@ -54,12 +56,14 @@ "react-native-super-grid": "^4.6.1", "react-native-svg": "13.4.0", "react-native-testing-library": "^6.0.0", + "react-native-url-polyfill": "^1.3.0", "react-native-web": "~0.18.7", "react-redux": "^8.0.2", "react-timer-hook": "^3.0.5", "react-use-precision-timer": "^3.3.1", "redux-persist": "^6.0.0", "soundfont-player": "^0.12.0", + "standardized-audio-context": "^25.3.51", "type-fest": "^3.6.0", "yup": "^0.32.11" }, diff --git a/front/tsconfig.json b/front/tsconfig.json index 6569689..7230ee3 100644 --- a/front/tsconfig.json +++ b/front/tsconfig.json @@ -13,7 +13,7 @@ /* Language and Environment */ "target": "esnext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - "lib": ["es2019"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "lib": ["es2019", "DOM"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ "jsx": "react-native", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ diff --git a/front/views/HomeView.tsx b/front/views/HomeView.tsx index 0e51347..ae85d81 100644 --- a/front/views/HomeView.tsx +++ b/front/views/HomeView.tsx @@ -139,7 +139,7 @@ const HomeView = () => { } { [...(new Set(searchHistoryQuery.data.map((x) => x.query)))].slice(0, 5).map((query) => ( - + /> )) } diff --git a/front/views/PlayView.tsx b/front/views/PlayView.tsx index eadc03c..2a0ac41 100644 --- a/front/views/PlayView.tsx +++ b/front/views/PlayView.tsx @@ -18,6 +18,10 @@ import { ColorSchemeType } from 'native-base/lib/typescript/components/types'; import { useStopwatch } from "react-use-precision-timer"; import PartitionView from '../components/PartitionView'; import TextButton from '../components/TextButton'; +import { MIDIAccess, MIDIMessageEvent, requestMIDIAccess } from "@motiz88/react-native-midi"; +import * as Linking from 'expo-linking'; +import { URL } from 'url'; +import { url } from 'inspector'; type PlayViewProps = { songId: number, @@ -34,19 +38,25 @@ type ScoreMessage = { let scoroBaseApiUrl = Constants.manifest?.extra?.scoroUrl; if (process.env.NODE_ENV != 'development' && Platform.OS === 'web') { - if (location.protocol === 'https:') { - scoroBaseApiUrl = "wss://" + location.host + "/ws"; - } else { - scoroBaseApiUrl = "ws://" + location.host + "/ws"; - } + + Linking.getInitialURL().then((url) => { + if (url !== null) { + const location = new URL(url); + if (location.protocol === 'https:') { + scoroBaseApiUrl = "wss://" + location.host + "/ws"; + } else { + scoroBaseApiUrl = "ws://" + location.host + "/ws"; + } + } + }); } -function parseMidiMessage(message) { +function parseMidiMessage(message: MIDIMessageEvent) { return { - command: message.data[0] >> 4, - channel: message.data[0] & 0xf, - note: message.data[1], - velocity: message.data[2] / 127, + command: message.data.at(0)! >> 4, + channel: message.data.at(0)! & 0xf, + note: message.data.at(1)!, + velocity: message.data.at(2)! / 127, }; } @@ -99,7 +109,7 @@ const PlayView = ({ songId, type, route }: RouteProps) => { })); } - const onMIDISuccess = (access) => { + const onMIDISuccess = (access: MIDIAccess) => { const inputs = access.inputs; if (inputs.size < 2) { @@ -159,9 +169,8 @@ const PlayView = ({ songId, type, route }: RouteProps) => { } } setLastScoreMessage({ content: formattedMessage, color: messageColor }); - // toast.show({ description: formattedMessage, placement: 'top', colorScheme: messageColor ?? 'secondary' }); } catch (e) { - console.log(e); + console.error(e); } } inputs.forEach((input) => { @@ -172,7 +181,6 @@ const PlayView = ({ songId, type, route }: RouteProps) => { const { command, channel, note, velocity } = parseMidiMessage(message); const keyIsPressed = command == 9;; const keyCode = message.data[1]; - // console.log('Playing midi ' + keyCode + ' at time ' + getElapsedTime()); webSocket.current?.send( JSON.stringify({ type: keyIsPressed ? "note_on" : "note_off", @@ -218,7 +226,7 @@ const PlayView = ({ songId, type, route }: RouteProps) => { return; } if (song.data && !webSocket.current && partitionRendered) { - navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure); + requestMIDIAccess().then(onMIDISuccess).catch(onMIDIFailure); } }, [song.data, partitionRendered]); diff --git a/front/views/settings/SettingsView.tsx b/front/views/settings/SettingsView.tsx index efcfbe3..f4c4f45 100644 --- a/front/views/settings/SettingsView.tsx +++ b/front/views/settings/SettingsView.tsx @@ -83,7 +83,7 @@ const SetttingsNavigator = () => { } return ( - + {/* I'm doing this to be able to land on the summary of settings when clicking on settings and directly to the wanted settings page if needed so I need to do special work with the 0 index */} diff --git a/front/yarn.lock b/front/yarn.lock index dbb3884..97d7753 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -1239,6 +1239,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.22.3": + version "7.22.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb" + integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ== + dependencies: + regenerator-runtime "^0.13.11" + "@babel/runtime@~7.5.4": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132" @@ -2344,6 +2351,13 @@ hey-listen "^1.0.8" tslib "^2.3.1" +"@motiz88/react-native-midi@^0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@motiz88/react-native-midi/-/react-native-midi-0.0.5.tgz#8162850a6ad501436376edef43889550e133986a" + integrity sha512-9IZeYqX1BEpI9iJZzoerEjHH4SM1whMls96A0/8dHxHydr35DkUzXxT0N99FibMT/32iRqF6cZgaPnS/duXNvw== + dependencies: + event-target-shim "^6.0.2" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -4753,7 +4767,7 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== -"@types/qs@^6.9.5": +"@types/qs@^6.5.3", "@types/qs@^6.9.5": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== @@ -5849,6 +5863,14 @@ audio-loader@^0.5.0: resolved "https://registry.yarnpkg.com/audio-loader/-/audio-loader-0.5.0.tgz#9c125d1b25c33cd9626084054d9f6b7f31ddc908" integrity sha512-mEoYRjZhqkBSen/X9i2PNosqvafEsur8bI5MNoPr0wsJu9Nzlul3Yv1elYeMPsXxTxYhXLY8AZlScBvaK4mydg== +automation-events@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/automation-events/-/automation-events-6.0.4.tgz#a308501319b9f921de7165e0b1a201b46cd1ab59" + integrity sha512-3C/7GtIB1rEwXfSEMUaJRZJFaDJWyiZ3g+Z1HWVAZj+SYZDGKZiZKTZ+Kfq0Lmnb0hL5RXtJ5prfMXbC10evzA== + dependencies: + "@babel/runtime" "^7.22.3" + tslib "^2.5.3" + autoprefixer@^9.8.6: version "9.8.8" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" @@ -6478,7 +6500,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.5.0: +buffer@^5.4.3, buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -8619,6 +8641,11 @@ event-target-shim@^5.0.0, event-target-shim@^5.0.1: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +event-target-shim@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-6.0.2.tgz#ea5348c3618ee8b62ff1d344f01908ee2b8a2b71" + integrity sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -8829,6 +8856,17 @@ expo-keep-awake@~11.0.1: resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-11.0.1.tgz#ee354465892a94040ffe09901b85b469e7d54fb3" integrity sha512-44ZjgLE4lnce2d40Pv8xsjMVc6R5GvgHOwZfkLYtGmgYG9TYrEJeEj5UfSeweXPL3pBFhXKfFU8xpGYMaHdP0A== +expo-linking@~3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-3.3.1.tgz#253b183321e54cb6fa1a667a53d4594aa88a3357" + integrity sha512-T3VIZMyZhkBOpHIyfT514rweGZZMbdg1vwavsfAkm6BFJ8G0iNVGbYMTpoUiQ9xdA0ARCcZbXFFb+WhqEUITgQ== + dependencies: + "@types/qs" "^6.5.3" + expo-constants "~14.0.0" + invariant "^2.2.4" + qs "^6.9.1" + url-parse "^1.5.9" + expo-manifests@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/expo-manifests/-/expo-manifests-0.4.0.tgz#6fd44b6427e113f2eb9409ca46df95cbbea068df" @@ -15120,6 +15158,13 @@ qs@6.11.0, qs@^6.10.0: dependencies: side-channel "^1.0.4" +qs@^6.9.1: + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + query-string@^6.13.6: version "6.14.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" @@ -15432,6 +15477,13 @@ react-native-testing-library@^6.0.0: dependencies: pretty-format "^26.0.1" +react-native-url-polyfill@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/react-native-url-polyfill/-/react-native-url-polyfill-1.3.0.tgz#c1763de0f2a8c22cc3e959b654c8790622b6ef6a" + integrity sha512-w9JfSkvpqqlix9UjDvJjm1EjSt652zVQ6iwCIj1cVVkwXf4jQhQgTNXY6EVTwuAmUjg6BC6k9RHCBynoLFo3IQ== + dependencies: + whatwg-url-without-unicode "8.0.0-3" + react-native-web@~0.18.7: version "0.18.12" resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.18.12.tgz#d4bb3a783ece2514ba0508d7805b09c0a98f5a8e" @@ -16796,6 +16848,15 @@ stacktrace-parser@^0.1.3: dependencies: type-fest "^0.7.1" +standardized-audio-context@^25.3.51: + version "25.3.51" + resolved "https://registry.yarnpkg.com/standardized-audio-context/-/standardized-audio-context-25.3.51.tgz#0eb54629355d1ddf2070897e586eaa8dfec8c0f5" + integrity sha512-+YPccvetw8wqWo0pv6lo5aDeUq+2WHL/S+8AWdrLKG1jMlhJZqK/GjNF/88q6jXAHal32Msc1xPx3uGrx8RPdQ== + dependencies: + "@babel/runtime" "^7.22.3" + automation-events "^6.0.4" + tslib "^2.5.3" + state-toggle@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" @@ -17631,6 +17692,11 @@ tslib@^2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@^2.5.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" + integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -18550,6 +18616,15 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-url-without-unicode@8.0.0-3: + version "8.0.0-3" + resolved "https://registry.yarnpkg.com/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz#ab6df4bf6caaa6c85a59f6e82c026151d4bb376b" + integrity sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig== + dependencies: + buffer "^5.4.3" + punycode "^2.1.1" + webidl-conversions "^5.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"