I'm currently working on a sound experiment, and I've come across one issue. I save an array of wave data to a .wav file and play it, but is there a way to skip this step and simply play the sound right from memory? I'm looking for a solution that will work cross-platform.
How to open a WAV file. Since WAV is quite a popular format, almost all devices today support it using built-in media players. On Windows, the Windows Media Player is capable of playing WAV files. On MacOS, iTunes or QuickTime can play WAV files.
WAV data is usually stored in files or resources in Resource Interchange File Format (RIFF). The data includes a description of the WAV format, including parameters such as the sampling rate and number of output channels. The format of a sound is described by a WaveFormat structure.
For Windows, if you double-click a WAV file, it will open using Windows Media Player. For Mac, if you double-click a WAV, it will open using iTunes or Quicktime. If you're on a system without these programs installed, then consider third-party software.
The current value of that wave is repeatedly measured and given as a number. That's the numbers in those bytes. There are two different things that can be adjusted with this: The number of measurements you take per second (that's the sampling rate, given in Hz -- that's how many per second you grab).
I suppose you are using the wave library, right?
The docs say:
wave.open(file[, mode])
If file is a string, open the file by that name, otherwise treat it as a seekable file-like object.
This means that you should be able to do something along the lines of:
>>> import wave
>>> from StringIO import StringIO
>>> file_on_disk = open('myfile.wav', 'rb')
>>> file_in_memory = StringIO(file_on_disk.read())
>>> file_on_disk.seek(0)
>>> file_in_memory.seek(0)
>>> file_on_disk.read() == file_in_memory.read()
True
>>> wave.open(file_in_memory, 'rb')
<wave.Wave_read instance at 0x1d6ab00>
EDIT (see comments): Just in case your issue is not only about reading a file from memory but playing it from python altogether...
An option is tu use pymedia
import time, wave, pymedia.audio.sound as sound
f= wave.open( 'YOUR FILE NAME', 'rb' ) # ← you can use StrinIO here!
sampleRate= f.getframerate()
channels= f.getnchannels()
format= sound.AFMT_S16_LE
snd= sound.Output( sampleRate, channels, format )
s= f.readframes( 300000 )
snd.play( s )
while snd.isPlaying(): time.sleep( 0.05 )
[source: the pymedia tutorial (for brevity I omitted their explanatory comments]
Creating a wav file with generated sine wave samples in memory and playing it on Windows:
import math
import struct
import wave
import winsound
import cStringIO as StringIO
num_channels = 2
num_bytes_per_sample = 2
sample_rate_hz = 44100
sound_length_sec = 2.0
sound_freq_hz = 500
memory_file = StringIO.StringIO()
wave_file = wave.open(memory_file, 'w')
wave_file.setparams((num_channels, num_bytes_per_sample, sample_rate_hz, 0, 'NONE', 'not compressed'))
num_samples_per_channel = int(sample_rate_hz * sound_length_sec)
freq_pos = 0.0
freq_step = 2 * math.pi * sound_freq_hz / sample_rate_hz
sample_list = []
for i in range(num_samples_per_channel):
sample = math.sin(freq_pos) * 32767
sample_packed = struct.pack('h', sample)
for j in range(num_channels):
sample_list.append(sample_packed)
freq_pos += freq_step
sample_str = ''.join(sample_list)
wave_file.writeframes(sample_str)
wave_file.close()
winsound.PlaySound(memory_file.getvalue(), winsound.SND_MEMORY)
memory_file.close()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With