Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to play WAV data right from memory?

Tags:

python

wav

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.

like image 347
Jordan Scales Avatar asked Nov 19 '11 16:11

Jordan Scales


People also ask

How do I listen to a WAV file?

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.

How is WAV data stored?

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.

How does a computer read a WAV file?

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.

What do the bytes in WAV file mean?

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).


2 Answers

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]

like image 138
mac Avatar answered Oct 16 '22 13:10

mac


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()
like image 32
Roger Dahl Avatar answered Oct 16 '22 14:10

Roger Dahl