New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wave.py: add writesamples() and readsamples() #49163
Comments
Corrected code in writeframesraw(): self._datawritten = self._datawritten + len(data) *
self._sampwidth
else:
self._file.write(data)
self._datawritten = self._datawritten + len(data) *
self._sampwidth Note that the default (not byte swapped) assignment to _datawritten must As a side note, the calls to _patchheader() do not need to be protected if self._datalength != self._datawritten: _patchheader does the same test to optimize its operation. |
Wave_read.initfp also needs fixing on counting the frame number, correct Patch added. |
Oops, _framesize already takes sampwidth into account. So there is a |
Given the name of the function related to the problem: "writeframesraw", Does that make sense to you Alex ? |
Ah, yes :) But in the other case (the one where it is currently So, besides the extras "if" statements all is good. |
Oh golly. I was confused. For some reason I was thinking So the current code reads ok. Which makes this "bug" a request for Here are python2.4-ish versions written for outside wave.py. Combos of 8 Sample values are expected to be +-32767 or +-128 ints (or +-2.x gig if def readsamples(wf, nframes) :
""" Read an array of number-of-channels normalized int sample
arrays. """
wav = wf.readframes(nframes)
if wf.getsampwidth() == 4 :
wav = struct.unpack("<%ul" % (len(wav) / 4), wav)
elif wf.getsampwidth() == 2 :
wav = struct.unpack("<%uh" % (len(wav) / 2), wav)
else :
wav = struct.unpack("%uB" % len(wav), wav)
wav = [ s - 128 for s in wav ]
nc = wf.getnchannels()
if nc > 1 :
wavs = []
for i in xrange(nc) :
wavs.append([ wav[si] for si in xrange(0, len(wav), nc) ])
pass
else :
wavs = [ wav ]
return(wavs)
def writesamples(wf, wavs) :
"""
Write samples to the wave file.
'wavs' looks like this:
[ left_channel_samples, right_channel_samples ]
or [ left_channel_samples ]
or mono_samples
This routine calls setnchannels() from information about 'wavs'
length.
"""
if wavs :
if len(wavs) not in [ 1, 2, 4 ] :
wavs = [ wavs, wv ]
wf.setnchannels(len(wavs))
if len(wavs) > 1 :
wav = []
for w in zip(*wavs):
wav += w
pass
else :
wav = wavs[0]
if wf.getsampwidth() == 4 :
ws = array.array('l', [ s for s in wav ])
elif wf.getsampwidth() == 2 :
ws = array.array('h', [ s for s in wav ])
else :
ws = array.array('B', [ s + 128 for s in wav ])
ws = ws.tostring()
wf.writeframes(ws)
# end of code to edit and insert in wave.py |
Oh gob. I left a debug artifact in that code. wavs = [ wavs, wv ] needs to be without the 'wv'. |
Documentation, tests and patch against trunk are needed to get this into |
I might be able to do doc/test/patch in a month or two, but know |
I could do it, but I'm in disagreement with big part of your patch. Can you add some kind of test you used for it ? Raw data, sample file, |
Polo: "I could do it, but I'm in disagreement with big part of your patch." Why surely you can't mean the bug. :) (The test program has it fixed.) What is the disagreement? Apparently this bug system allows file attachments, so I will upload a The program is hard coded to read the wave file and write a bunch of |
Aren't 8 bit samples stored as unsigned bytes ? If yes, they don't range Why is this check: "if len(wavs) not in [ 1, 2, 4 ]" needed ? Calling setnchannels inside writesamples looks very wrong to me, weren't I see writesamples is expecting "wavs" to be a list of lists containing The code layout didn't help me to get in agreement with it either. The above paragraphs are the things I disagree with the patch, hopefully |
"8 bit samples stored as unsigned bytes"? "if len(wavs) not in [ 1, 2, 4 ]" ? "Calling setnchannels"? "integers, is that the best format"? "The code layout"? "hand write the wave file for testing"? This code is not tested on a big-endian machine. I ran it under XP |
def readsamples(self, nframes) :
"""Return a list of lists of integers.
sampwidth = self.getsampwidth()
wav = struct.unpack(
'<%d%s' % (len(wav) / sampwidth, wave._array_fmts[sampwidth]),
wav)
nc = self.getnchannels()
if nc > 1:
wavs = []
for c in xrange(nc):
wavs.append([wav[si] for si in xrange(c, len(wav), nc)])
else:
wavs = [[wav]]
return wavs
def writesamples(self, *wavs) :
"""Write samples to the wave file.
wav = []
for w in zip(*wavs):
wav.extend(w)
ws = array.array(wave._array_fmts[self.getsampwidth()], wav)
ws = ws.tostring()
# we want all the samples in writeframes() format so that _convert
# can be called on them
self.writeframes(ws) You can monkey patch wave then by doing: wave.Wave_write.writesamples = writesamples
wave.Wave_read.readsamples = readsamples And then change some other parts of your code.
|
I was going to reply about your "code layout" answer but forgot. Well, The only problem is that there is no maintainer for wave.py, so, the |
"DC (0 hz) assumption"? "writesamples would raise an exception" "4) Well, lets fix a format then. else: wavs = [[wav]]" ? "wavs.extend(wav)" ? "monkey patch"?' "code layout"? "test_wave.py"? Gotta run now. But will try to update the code in wave_futz later. Other Guilherme, I really appreciate your handling this and your guidance. Thanks! |
Every document/text I've found so far talks about 8 bit samples being
It is good that it is just two lines, it means they could be added
Right.
It won't just do this optimization, keeping the special case for mono is fine.
I'm waiting for the new hand written tests now :) |
I'll upload the latest monkey-patch file, wave_futz.py, and I found a 64-bit bug in the wave.py formats for 32-bit sample wave files. The pcm files read in to CoolEdit ok, including the 32-bit sample files. |
Please upload plain-text files with unique names for each file uploaded. |
Here go, Terry. Copies of the two files in the latest ZIP file. Hmmm. Well. Maybe just one of 'em. Looks like the only way to upload files is to add a msg, so I'll upload the other file in another msg. |
OK, here's the other. |
Forgive my unfamiliarity with python's development process, but, what is happening with this? Is there any chance of this enhancement making it into the python libs? What would need to happen? Thanks. |
Someone has to find the time to do a commit review on the patch. As Guilherme said, there's no specific maintainer for wave, so I'm afraid it just got forgotten about. On the other hand, as a new feature it would now go in 3.5, and we're at the start of the approximately one year window for new features, so if you ping this issue (as you just did) periodically, someone will get to it ;) What you could do to help move it along is to do your own review of the patch, including making sure it still applies to default...which it may not, since there have in fact been some changes in wave.py. If that's the case you can also help by updating the patch. |
Serhiy, is this something you can review? |
On quickly looking at this, the immediate issue seems to me to be that there is no patch, as I understand the term. If it would be helpful I can look at turning the code in the attached files into a patch against default and ensure the tests pass (but not right now as it's ~1am here). |
A patch against default, including a test, would be helpful. |
I hope all mentioned bugs were already fixed in the wave module. As for new writesamples() and readsamples() methods, perhaps it would be better to add utility functions in the audioop module for packing/unpacking integers. In any case a user can use array.array. |
It's been ~8 years since the most recent request for a patch with no action, perhaps this issue can be closed as there seems to be no need for the feature? A |
+1; closing. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: