react-native-pure-data
v0.0.1-alpha.1
Published
🔈 ⚡ Synthesize algorithmic sound at runtime in React Native.
Downloads
63
Maintainers
Readme
react-native-pure-data
A native wrapper for libpd-ios
and libpd-android
, which enables you to rapidly prototype DSP algorithms described using Pure Data, an industry standard open source visual programming language capable of synthesising audiovisual effects.
react-native-pure-data
enables the synthesis of generative audio, which helps developers achieve dynamic sound at runtime. This is useful for games, music production and communications.
Key Features
- Patches in Pure Data can be interacted with via React component props.
- Simultaneous patch execution.
- Supports hot reloading, so DSP algorithms can be prototyped directly using Pure Data's interface and then executed concurrently on an Android/iOS device or emulator.
- Loaded patches respect the Component Lifecycle, so they can be mounted or unmounted as expected.
⚠️ Warning
Please be extremely cautious when prototyping using this library.
Pd is capable of generating high amplitude sound waves, which can damage your hearing if you choose to listen using headphones.
Please take care to minimize the risk of hearing damage or loss as much as possible by playing back on external speakers at a reduced volume whenever prototyping with new patches or props. In addition, you must always consider the volume of the end user's device.
And remember,
With great power, comes great responsibility. - Linus Torvalds
🚀 Getting Started
1. Installing
Using npm
:
npm install --save react-native-pure-data
Using yarn
:
yarn add react-native-pure-data
For versions of React Native less than 0.60, after installation has complete you must execute react-native link
to make the native library dependencies visible to your compiled application.
2. Update metro.config.js
Once installed, you'll need to update your metro.config.js
to help the Metro Bundler load your patches:
+const metroDefault = require('metro-config/src/defaults/defaults.js');
module.exports = {
resolver: {
+ assetExts: metroDefault.assetExts.concat(['pd']),
},
};
This will enable hot loading, so you can modify your patches even whilst they're being rendered by the app.
After making this change, you'll need to restart the bundler.
3. Runtime Specific
3.1 iOS
After installing this library, you'll need reinstall the iOS cocoapods. First, enter your app's /ios
directory. Then use:
pod install # update cocoapods
cd ..
react-native run-ios
3.2 Android
Android is not yet supported, but will be released this weekend.
✍️ Example
react-native-pure-data
exposes just two Components; AudioController
and Patch
. The former is used for general sound output configuration, and the latter is used to load and interact with a patch written in Pure Data.
The simplest example is a patch which does not rely on any data from your App.js
; you'll see here, that all we need to do is define an <AudioController />
at the root of the application, and declare the Patch
's file source.
import React from "react";
import {AudioController, Patch} from "react-native-pure-data";
import SomePatch from "./patches/some-patch.pd";
export default () => (
<AudioController
active
>
<Patch
source={SomePatch}
/>
</AudioController>
);
However, Pure Data is uses an asynchronous, message-driven protocol. This normally means that imported patches will need to be either triggered or configured by your runtime logic.
To communicate with a loaded patch from your app, all you have to do is specify additional props on the Patch
component. These will be synchronously routed to corresponding receivers in the Pure Data patch whenever the component is re-rendered:
import React, {useState, useEffect} from "react";
import {AudioController, Patch} from "react-native-pure-data";
import SomePatch from "./patches/some-patch.pd";
export default () => {
const [frequency, setFrequency] = useState(440);
useEffect(
() => {
/* every 1000ms, set a new frequency */
const i = setInterval(
() => setFrequency(Math.random() * 1000),
1000,
);
return () => clearInterval(i);
},
[],
);
return (
<AudioController
active
>
<Patch
source={SomePatch}
nextFrequency={frequency}
/>
</AudioController>
);
};
In the example above, a random frequency will be calculated and transmitted to the corresponding receiver on the diagram. In this case, the receiver would be called "nextFrequency", which would be declared using a Pure Data Object with the definition [r nextFrequency]
:
The convention used here is that for every numeric prop, the name of that prop corresponds to the message receiver within the patch.
Therefore, if we defined an additional prop named someOtherFrequency={Math.random()}
, whenever the component is re-rendered we would send a message to the receiver [r someOtherFrequency]
that existed within the patch. If the receiver does not exist, this is a noop.
Please check out the Example App for further details.