'How to manipulate .wav files in a React Native Expo project?

My group and I are currently working on a mobile application project focused around audio editing features, mainly the ability to overlay audio files over other. The main goal is to be able to record music over pre existing music.

We have figured out how to record audio through the iPhone and convert the m4a to a vnd.wav file.

After talking to our project sponsors, they suggested we load the file into an array and play around with the array to figure out how to manipulate the audio (ie looping the samples backwards to be able to reverse a track).

Each of us have searched google endlessly to figure out a library that works in Expo that will allow us to pull the audio samples into an array. Our sponsor gave us some code to do so through Python, but it uses Numpy which Expo does not support. Here is the Python code below (we confirmed it pulls the samples for us given a .wav or vnd.wav):

import numpy as np


# NOTE: numpy.fromfile is what I use to read bytes, shorts, or int32. You'll have to find the equivalent in
# js, which I'm sure exists. read the doc on numpy fromfile for the meaning of each argument.

def findChunk(fileName,off,chunkName=None):
    # Aux function to skip chunks in wav file header until you get to the right one.
    if chunkName is None: chunkName = ''
    while 1:
        sbName = np.fromfile(fileName, np.uint8, 4, "", off)
        if not len(sbName): return 0,0,""
        # python's contorted way to make a string out of 4 chars in the present case.
        sbNameS = ''.join([chr(item) for item in sbName])
        # Read the size of the chunk, a 32 bit int.
        sbSize = np.fromfile(fileName, np.int32, 1, "", off+4)
        sbSize=sbSize[0]
        # Increment offset by 4 (4 for the chunk name, 4 for the chunk size)
        off += 8
        if sbNameS == chunkName or chunkName == '': break
        # and increment offset by the chunk data size.
        off += sbSize
    return off, sbSize, sbNameS

def npReadWavFile(fileName):
    # A very simple function that allows reading wav files directly in numpy
    # Find the fmt subchunk, that's where you can read the sampling rate, the number of channels etc.
    off = 12
    off, sbSize, name = findChunk(fileName,off,'fmt ')

    # format is a 16 bit int.
    format, = np.fromfile(fileName, np.uint16, 1, "", off)
    if format != 1 and format != 3:
        print("Warning: WAVFORMAT = %d"%format) # See https://github.com/tpn/winddk-8.1/blob/master/Include/shared/mmreg.h.
    # 1=PCM.
    numChans, = np.fromfile(fileName, np.int16, 1, "", off+2)
    sRate, = np.fromfile(fileName, np.int32, 1, "", off+4)
    bps, = np.fromfile(fileName, np.int16, 1, "", off+14)
    off += sbSize
    # Now find the data subchunk. That's where the samples are. In some wavfile it's right after the fmt chunk, but
    # not always!
    off, subchunkSize, name = findChunk(fileName, off, 'data')
    if bps == 16:
        # This is the most standard wav format: 16 bit integer.
        subchunkSize = subchunkSize//2
        x = np.fromfile(fileName, np.int16,subchunkSize, "", off)
        if len(x) < subchunkSize:
            print("Warning, could not read enough samples, incorrect header")
        x = x[0:(len(x)//numChans)*numChans].reshape((len(x) // numChans, int(numChans))) / 32767.0
    else:
        x = np.zeros((0 * bps, 0*bps)) # <- This is for pythran, you can't put a compile-time knowable shape here
        print('Only 16 bit wav files are supported. Bits per sample: %d' % bps)
    return x, sRate

if __name__ == '__main__':
    import argparse
    
    parser = argparse.ArgumentParser('wav_file', description='Loads a wavfile')
    parser.add_argument('thisFile', help='This file')  # For a positional argument.
    args = parser.parse_args()

    x,sRate = npReadWavFile(args.thisFile)
    print(f"Read file {args.thisFile}, found {len(x)} samples, sample rate {sRate}")


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source