tamlyn / react-native-elementary

Use Elementary Audio in your React Native app
MIT License
10 stars 3 forks source link

Adding sample/vfs support #10

Open ebenoist opened 4 months ago

ebenoist commented 4 months ago

Elementary has basic support for loading samples into a "file system". I'd like to expose those APIs via the react-native-elementary library. I'm currently building an API that looks like this in iOS:

RCT_EXPORT_METHOD(loadAudioResource:(NSString *) path
        resolver:(RCTPromiseResolveBlock) resolve
        rejecter:(RCTPromiseRejectBlock) reject)
{
// ...

}

I want to pull this into the shared adapter so I use it in both android and ios implementations. Any thoughts about the method signature? I'm all ears.

txbrown commented 3 months ago

@ebenoist I wonder if we can leverage from the new architecture and use Turbo Modules instead of the Module bridge pattern. I think this would allow us to have better method signatures and strongly typed on typescript / js side too. I am happy to support as well!

erik-nilcoast commented 3 months ago

I think that's a great idea. I've paused this project for now, but getting basic VFS support in place would be a great asset. I go back and forth between the need to use react-native as that bridge, using the web implementation, or continuing to patch directly into the elementary cpp adapter.

I think something like this could work, but I would need to test it out. I don't love the method signature, but I'm not sure how best to pass back jsobject that can be serialized into a js Object for the callback.

ELEM_EXPORT void elem_runtime_float_load_audio_resource(
    const char* path,
    void (*callback)(void* data, const int channels, const int sampleRate))
 {
    elem::js::Array channelData;

    unsigned int channels;
    unsigned int sampleRate;
    drwav_uint64 frameCount;

    float* rawData = drwav_open_file_and_read_pcm_frames_f32(
        path,
        &channels,
        &sampleRate,
        &frameCount,
        nullptr
    );

    for (size_t i = 0; i < static_cast<size_t>(channels); ++i) {
        elem::js::Array sampleData;

        for (size_t j = 0; j < static_cast<size_t>(frameCount); ++j) {
            auto next = rawData[i + j * static_cast<size_t>(channels)];
            sampleData.push_back(next);
        }

        channelData.push_back(sampleData.data());
    }

    drwav_free(rawData, nullptr);

    callback(channelData.data(), channels, sampleRate);
}
txbrown commented 3 weeks ago

@ebenoist @erik-nilcoast any progress on this in your private projects? Any new info you can share? I want to help here but haven't had enough time so any insights are appreciated.