Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ check out the [Getting Started](https://docs.swmansion.com/react-native-audio-ap
Simple ability to play and buffer audio, with all of the most commonly used functions, same as on the web, without the need to create and manipulate an audio graph.

- **MIDI support 🎸**<br />
Complementary lib for react-native-audio-api, that will allow to communicate with MIDI devices or read/write MIDI files.
Complementary lib for react-native-audio-api, that will allow to communicate with MIDI devices.

- **Spatial Audio 🛢️**<br />
manipulate audio in 3D space
Expand Down
118 changes: 118 additions & 0 deletions apps/common-app/src/examples/Midi/Midi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React, { JSX } from 'react';
import { MIDIInput, requestMIDIAccess } from 'react-native-medi';
import { Button, View, Text, ScrollView } from 'react-native';
import { Container } from '../../components';
import { colors } from '../../styles';


function getColoredMidiMessage(data: Uint8Array): JSX.Element {
// Map MIDI message types to colors
// each message is 3 bytes: [status, data1, data2]
// statuses:
// 128, 135 - Note Off (red)
// 144, 151 - Note On (green)
// 176, 183 - Control Change (dark purple)
// others - default color
const status = data[0];
const RED = '#FF5555';
const GREEN = '#55FF55';
const DARK_PURPLE = '#AA00AA';
const DEFAULT_COLOR = '#AAAAAA'; // gray

let color;
if (status >= 128 && status <= 135) {
color = RED;
} else if (status >= 144 && status <= 151) {
color = GREEN;
} else if (status >= 176 && status <= 183) {
color = DARK_PURPLE;
} else {
color = DEFAULT_COLOR;
}

return <Text style={{ color }}>{`${Array.from(data).join(', ')}`}</Text>;
}

const Medi: React.FC = () => {
const [sourcePorts, setSourcePorts] = React.useState<MIDIInput[]>([]);
const [connectedPort, setConnectedPort] = React.useState<MIDIInput | null>(null);
const [messageLog, setMessageLog] = React.useState<JSX.Element[]>([]);
const scrollViewRef = React.useRef<ScrollView>(null);

const scanMIDIDevices = async () => {
const access = await requestMIDIAccess();
setSourcePorts(access.inputs);
};

const connectToPort = async (portId: string) => {
if (connectedPort) {
await connectedPort.close();
}
const access = await requestMIDIAccess();
const input = access.inputs.find((port) => port.id === portId);
if (input) {
await input.open();
input.onmidimessage = (message: Uint8Array) => {
setMessageLog((prevLog) => [...prevLog, getColoredMidiMessage(message)]);
};
setConnectedPort(input);
console.log(`Connected to MIDI Input Port: ${portId}`);
} else {
console.log(`MIDI Input Port not found: ${portId}`);
setConnectedPort(null);
}
};

const disconnectPort = async () => {
if (connectedPort) {
await connectedPort.close();
setConnectedPort(null);
setMessageLog([]);
console.log(`Disconnected from MIDI Input Port`);
}
}

return (
<Container>
<View style={{ flex: 1, alignItems: 'center' }}>
<View style={{ width: '80%' }}>
<Button title="Scan MIDI Devices" onPress={scanMIDIDevices} />
<View style={{ flexDirection: 'column', gap: 10, marginTop: 10 }}>
{connectedPort ? (
<Button title="Disconnect MIDI Device" onPress={disconnectPort} />
) : (
sourcePorts.map((port) => (
<Button key={port.id} title={`Connect to ${port.name}`} onPress={async () => await connectToPort(port.id)} />
))
)}
</View>
</View>
<View style={{ marginTop: 20, borderWidth: 1, borderColor: '#000', padding: 10, borderRadius: 5, width: '80%', height: 300 }}>
<Text style={{ fontWeight: 'bold', textAlign: 'center', color: colors.white }}>Connected Port: {connectedPort ? connectedPort.name : 'None'}</Text>
<ScrollView
ref={scrollViewRef}
style={{ width: '100%', marginTop: 10 }}
onContentSizeChange={() => scrollViewRef.current?.scrollToEnd({ animated: true })}
>
{messageLog.map((msg, index) => (
<View key={index}>
{msg}
</View>
))}
</ScrollView>
</View>
<View style={{ marginTop: 20, width: '80%' }}>
<Button
title="Clear Logs"
onPress={() => {
setMessageLog([]);
}}
/>
</View>
</View>

</Container>
);
};

export default Medi;
8 changes: 8 additions & 0 deletions apps/common-app/src/examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Record from './Record/Record';
import PlaybackSpeed from './PlaybackSpeed/PlaybackSpeed';
import Worklets from './Worklets/Worklets';
import Streaming from './Streaming/Streaming';
import MediTest from './Midi/Midi';

type NavigationParamList = {
Oscillator: undefined;
Expand All @@ -25,6 +26,7 @@ type NavigationParamList = {
Record: undefined;
Worklets: undefined;
Streamer: undefined;
MediTest: undefined;
};

export type ExampleKey = keyof NavigationParamList;
Expand All @@ -38,6 +40,12 @@ export interface Example {
}

export const Examples: Example[] = [
{
key: 'MediTest',
title: 'Medi Test',
subtitle: 'Test react-native-medi turbo module',
screen: MediTest,
},
{
key: 'DrumMachine',
title: 'Drum Machine',
Expand Down
58 changes: 29 additions & 29 deletions apps/fabric-example/ios/FabricExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
0C80B921A6F3F58F76C31292 /* libPods-FabricExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-FabricExample.a */; };
08E56AF36CF95F801B98BC2E /* libPods-FabricExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F588A5D656DE625BDAE2171 /* libPods-FabricExample.a */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
Expand All @@ -19,11 +19,11 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = FabricExample/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = FabricExample/Info.plist; sourceTree = "<group>"; };
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = FabricExample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3B4392A12AC88292D35C810B /* Pods-FabricExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FabricExample.debug.xcconfig"; path = "Target Support Files/Pods-FabricExample/Pods-FabricExample.debug.xcconfig"; sourceTree = "<group>"; };
5709B34CF0A7D63546082F79 /* Pods-FabricExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FabricExample.release.xcconfig"; path = "Target Support Files/Pods-FabricExample/Pods-FabricExample.release.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-FabricExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FabricExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
1473584ADAA43A1816657BC0 /* Pods-FabricExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FabricExample.debug.xcconfig"; path = "Target Support Files/Pods-FabricExample/Pods-FabricExample.debug.xcconfig"; sourceTree = "<group>"; };
5F588A5D656DE625BDAE2171 /* libPods-FabricExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FabricExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = FabricExample/AppDelegate.swift; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = FabricExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
A52104CC00DFB2C78BFADFFB /* Pods-FabricExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FabricExample.release.xcconfig"; path = "Target Support Files/Pods-FabricExample/Pods-FabricExample.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */

Expand All @@ -32,7 +32,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0C80B921A6F3F58F76C31292 /* libPods-FabricExample.a in Frameworks */,
08E56AF36CF95F801B98BC2E /* libPods-FabricExample.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -55,7 +55,7 @@
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
5DCACB8F33CDC322A6C60F78 /* libPods-FabricExample.a */,
5F588A5D656DE625BDAE2171 /* libPods-FabricExample.a */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -92,8 +92,8 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
3B4392A12AC88292D35C810B /* Pods-FabricExample.debug.xcconfig */,
5709B34CF0A7D63546082F79 /* Pods-FabricExample.release.xcconfig */,
1473584ADAA43A1816657BC0 /* Pods-FabricExample.debug.xcconfig */,
A52104CC00DFB2C78BFADFFB /* Pods-FabricExample.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
Expand All @@ -105,13 +105,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "FabricExample" */;
buildPhases = (
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
01D90308C1C7629E7B147A9B /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
810469A4ED5FD57E4C4493F1 /* [CP] Embed Pods Frameworks */,
E784823DF297E043EC18828E /* [CP] Copy Pods Resources */,
);
buildRules = (
);
Expand Down Expand Up @@ -183,46 +183,46 @@
shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
};
00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = {
01D90308C1C7629E7B147A9B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-FabricExample/Pods-FabricExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-FabricExample/Pods-FabricExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-FabricExample-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FabricExample/Pods-FabricExample-frameworks.sh\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = {
810469A4ED5FD57E4C4493F1 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-FabricExample/Pods-FabricExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-FabricExample-checkManifestLockResult.txt",
"${PODS_ROOT}/Target Support Files/Pods-FabricExample/Pods-FabricExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FabricExample/Pods-FabricExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
E784823DF297E043EC18828E /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
Expand Down Expand Up @@ -255,7 +255,7 @@
/* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-FabricExample.debug.xcconfig */;
baseConfigurationReference = 1473584ADAA43A1816657BC0 /* Pods-FabricExample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
Expand Down Expand Up @@ -284,7 +284,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-FabricExample.release.xcconfig */;
baseConfigurationReference = A52104CC00DFB2C78BFADFFB /* Pods-FabricExample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
Expand Down
Loading