bastibe / python-soundfile

SoundFile is an audio library based on libsndfile, CFFI, and NumPy
BSD 3-Clause "New" or "Revised" License
676 stars 105 forks source link

Pass Raw Data To Write Function #395

Closed Fretless14 closed 1 year ago

Fretless14 commented 1 year ago

Is there a way to pass raw data directly to the write function without reading from a file?

I'm trying to make a workaround for pydub's inability to write 24bit files, and would be great to use pydub for some processing, then export with soundfile if the bit depth is 24bit / sample width of 3.

Fretless14 commented 1 year ago

I guess my question is more, how can I convert a byte string of the data (not array like, interleaved data for stereo or just mono) into the form soundfile accepts?

For example, starting with this byte string b'\x00\x00\x00\x00\x00\x00 that contains one channel of 24bit audio? (number of channels is known before this conversion)

Fretless14 commented 1 year ago

I think I have it for mono data from pydub (byte string of mono data) thanks to chatGPT:

data = audio_segment._data
data_array = np.frombuffer(data, dtype=np.int32) 
# must use int32 since int24 doesnt exist for np. dont worry, same data values

data_array = data_array.reshape(-1, 1) # -1 for all data, 1 for 1 channel

soundfile.write(file=new_filepath, data=data_array, samplerate=new_samplerate, subtype='PCM_24')

Working on stereo data, having some trouble since I don't fully understand how to get the values into numpy arrays/the parsing of the data

Fretless14 commented 1 year ago

Oh wow it's just changing the '1' in the reshape function to 2... I swear I tried that and I ended up with noise when playing the file... But it seems to work with this!

Would be great if someone were to check me on this! For stereo:

data = audio_segment._data
data_array = np.frombuffer(data, dtype=np.int32) 
# must use int32 since int24 doesnt exist for np. dont worry, same data values

data_array = data_array.reshape(-1, 2) # -1 for all data, 1 for 1 channel

soundfile.write(file=new_filepath, data=data_array, samplerate=new_samplerate, subtype='PCM_24')
bastibe commented 1 year ago

That looks about right.

This will write 24 bit data, but it assumes the original data is 32 bit. Is that as intended?

Fretless14 commented 1 year ago

Yep! Pydub reads 24bit audio as 32bit fixed, so this is just a workaround to export 24bit files from Pydub.

bastibe commented 1 year ago

Wonderful!