python-soundfile
                                
                                 python-soundfile copied to clipboard
                                
                                    python-soundfile copied to clipboard
                            
                            
                            
                        Read/write file from memory
I am trying to record some content, and instead of writing to disk, instead use a memory file.
So far I have the following, but I am getting an error with sf.read.
import soundfile   as sf
import sounddevice as sd
import os
import io
fs = 44100
seconds = 5
print( "recording..." )
recording = sd.rec( int ( seconds * fs ), samplerate = fs, channels = 1 )
sd.wait( )
file_format = "WAV"
memory_file = io.BytesIO( )
sf.write( memory_file, recording, fs, format = file_format )
# This works, and file can be played back
with open( "test.wav", 'wb' ) as f:
	f.write( memory_file.getbuffer( ) )
# This also works
temp_data, temp_sr = sf.read( "test.wav" )
# Playback is correct here too
sd.play( temp_data, temp_sr )
sd.wait( )
# This does not work?
temp_data, temp_sr = sf.read( memory_file )
The error from the final line:
  File "python3.9/site-packages/soundfile.py", line 1357, in _error_check
    raise RuntimeError(prefix + _ffi.string(err_str).decode('utf-8', 'replace'))
RuntimeError: Error opening <_io.BytesIO object at 0x1045b2180>: File contains data in an unknown format.
What would be the correct way to read data from memory?
Since memory_file does not have a file extension, you need to tell it to interpret it as a WAV file.
Thank you for the reply.
I have had a bit more time to dig into how SoundFile works, and looked at what it was doing internally. It seems that everything is working, and that it was correctly picking up the memory_file as virtual IO, however libsndfile was throwing the error.
This occurs because the memory_file internal stream has not been reset to the start, so when libsndfile tries to read from the stream, it receives empty bytes and throws the error. Adding a memory_file.seek( 0 ) to the after the write to the memory_file solves the above issue.
Please feel free to close the ticket if needed.
Final working code
import soundfile   as sf
import sounddevice as sd
import os
import io
fs = 44100
seconds = 5
print( "recording..." )
recording = sd.rec( int ( seconds * fs ), samplerate = fs, channels = 1 )
sd.wait( )
file_format = "WAV"
memory_file = io.BytesIO( )
memory_file.name = "test.wav"
sf.write( memory_file, recording, fs, format = file_format )
memory_file.seek( 0 )
# This now works
temp_data, temp_sr = sf.read( memory_file )
sd.play( temp_data, temp_sr )
sd.wait( )
Thank you for the follow-up! Would you like to contribute that gotcha to the documentation of soundfile's virtual-IO?
Thank you very much for your issue, which has helped me a lot.
Thank you guys! You really helped me to convert OGG to WAV and send it to REST API without disturbing the filesystem!
import io
import soundfile as sf
def ogg2wav(ogg: bytes):
    ogg_buf = io.BytesIO(ogg)
    ogg_buf.name = 'file.ogg'
    data, samplerate = sf.read(ogg_buf)
    wav_buf = io.BytesIO()
    wav_buf.name = 'file.wav'
    sf.write(wav_buf, data, samplerate)
    wav_buf.seek(0)
    return wav_buf.read()
if someone will search that too... that's how you can convert ogg to wav without touching the disk
Using file_like.seek(0) after sf.write(file_like, ...) solved the issue of seemingly not being able to write to in-memory files for me, too.
@bastibe Mentioning that this is required in the Virtual IO docs would have been really helpful. The above code snippet would be a sufficient example, I think. Or maybe it could be called automatically by default. 🤷♂️
Schöne Grüße 😉
I'm glad you found a solution! @jneuendorf-i4h would you like to contribute the change as a pull request?
Ebenfalls schöne Grüße!