From: Uwe Hermann Date: Sat, 18 Jan 2014 18:15:41 +0000 (+0100) Subject: i2s: Add WAV dump support, drop obsolete 'i2s_dump' PD. X-Git-Tag: libsigrokdecode-0.3.0~161 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=e54f222c4edf55a379e5b3ad892cf671ace83e48;p=libsigrokdecode.git i2s: Add WAV dump support, drop obsolete 'i2s_dump' PD. The functionality of the preliminary 'i2s_dump' PD is now available in the proper 'i2s' PD, via the OUTPUT_BINARY mechanism that frontends can use to dump decoded data (in various formats) to a file, or pipe it into other applications, and so on. Old sigrok-cli example usage: $ sigrok-cli -i 2ch-16bit-16khz.sr \ -P i2s:sck=0:ws=1:sd=2,i2s_dump:filename=foo.wav $ aplay foo.wav New sigrok-cli example usage: $ sigrok-cli -i 2ch-16bit-16khz.sr \ -P i2s:sck=0:ws=1:sd=2 -B i2s=wav > foo.wav $ aplay foo.wav New sigrok-cli example usage (piping into other applications): $ sigrok-cli -i 2ch-16bit-16khz.sr \ -P i2s:sck=0:ws=1:sd=2 -B i2s=wav | aplay - --- diff --git a/decoders/i2s/pd.py b/decoders/i2s/pd.py index 9f04e10..c934b5d 100644 --- a/decoders/i2s/pd.py +++ b/decoders/i2s/pd.py @@ -56,6 +56,9 @@ class Decoder(srd.Decoder): ['right', 'Right channel'], ['warnings', 'Warnings'], ] + binary = ( + ('wav', 'WAV file'), + ) def __init__(self, **kwargs): self.samplerate = None @@ -67,9 +70,11 @@ class Decoder(srd.Decoder): self.first_sample = None self.start_sample = None self.wordlength = -1 + self.wrote_wav_header = False def start(self): self.out_proto = self.register(srd.OUTPUT_PYTHON) + self.out_bin = self.register(srd.OUTPUT_BINARY) self.out_ann = self.register(srd.OUTPUT_ANN) def metadata(self, key, value): @@ -79,6 +84,9 @@ class Decoder(srd.Decoder): def putpb(self, data): self.put(self.start_sample, self.samplenum, self.out_proto, data) + def putbin(self, data): + self.put(self.start_sample, self.samplenum, self.out_bin, data) + def putb(self, data): self.put(self.start_sample, self.samplenum, self.out_ann, data) @@ -96,6 +104,33 @@ class Decoder(srd.Decoder): return 'I²S: %d %d-bit samples received at %sHz' % \ (self.samplesreceived, self.wordlength, samplerate) + def wav_header(self): + # Chunk descriptor + h = b'RIFF' + h += b'\x24\x80\x00\x00' # Chunk size (2084) + h += b'WAVE' + # Fmt subchunk + h += b'fmt ' + h += b'\x10\x00\x00\x00' # Subchunk size (16 bytes) + h += b'\x01\x00' # Audio format (0x0001 == PCM) + h += b'\x02\x00' # Number of channels (2) + h += b'\x80\x3e\x00\x00' # Samplerate (16000) + h += b'\x00\x7d\x00\x00' # Byterate (32000) + h += b'\x04\x00' # Blockalign (4) + h += b'\x10\x00' # Bits per sample (16) + # Data subchunk + h += b'data' + h += b'\xff\xff\x00\x00' # Subchunk size (65535 bytes) TODO + return h + + def wav_sample(self, sample): + # TODO: This currently assumes U32 samples, and converts to S16. + s = sample >> 16 + if s >= 0x8000: + s -= 0x10000 + lo, hi = s & 0xff, (s >> 8) & 0xff + return bytes([lo, hi]) + def decode(self, ss, es, data): if self.samplerate is None: raise Exception("Cannot decode without samplerate.") @@ -118,6 +153,11 @@ class Decoder(srd.Decoder): # Only submit the sample, if we received the beginning of it. if self.start_sample != None: + + if not self.wrote_wav_header: + self.put(0, 0, self.out_bin, (0, self.wav_header())) + self.wrote_wav_header = True + self.samplesreceived += 1 idx = 0 if self.oldws else 1 @@ -128,6 +168,7 @@ class Decoder(srd.Decoder): self.putpb(['DATA', [c3, self.data]]) self.putb([idx, ['%s: %s' % (c1, v), '%s: %s' % (c2, v), '%s: %s' % (c3, v), c3]]) + self.putbin((0, self.wav_sample(self.data))) # Check that the data word was the correct length. if self.wordlength != -1 and self.wordlength != self.bitcount: diff --git a/decoders/i2s_dump/__init__.py b/decoders/i2s_dump/__init__.py deleted file mode 100644 index 6b24953..0000000 --- a/decoders/i2s_dump/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Uwe Hermann -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -## - -''' -TODO. -''' - -from .pd import * - diff --git a/decoders/i2s_dump/pd.py b/decoders/i2s_dump/pd.py deleted file mode 100644 index 1661acb..0000000 --- a/decoders/i2s_dump/pd.py +++ /dev/null @@ -1,104 +0,0 @@ -## -## This file is part of the libsigrokdecode project. -## -## Copyright (C) 2013 Uwe Hermann -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -## - -import sigrokdecode as srd -import os -import sys - -class Decoder(srd.Decoder): - api_version = 1 - id = 'i2s_dump' - name = 'I²S dump' - longname = 'I²S dump' - desc = 'Output decoded I²S data to a file.' - license = 'gplv2+' - inputs = ['i2s'] - outputs = [] - probes = [] - optional_probes = [] - options = { - 'format': ['File format for the output data', 'wav'], - 'filename': ['File name for the output data', '-'], - } - annotations = [] - - def __init__(self, **kwargs): - self.wrote_header = False - self.f = None - - def file_open(self, filename): - if filename == 'none': - return None - elif filename == '-': - return sys.stdout - else: - return open(filename, 'wb') - - def start(self): - # A filename of 'none' is not allowed (has special meaning). A filename - # of '-' means 'stdout'. - self.f = self.file_open(self.options['filename']) - - # TODO: Lots of hard-coded fields in here. - def write_wav_header(self): - # Chunk descriptor - self.f.write(b'RIFF') - self.f.write(b'\x24\x80\x00\x00') # Chunk size (2084) - self.f.write(b'WAVE') - - # Fmt subchunk - self.f.write(b'fmt ') - self.f.write(b'\x10\x00\x00\x00') # Subchunk size (16 bytes) - self.f.write(b'\x01\x00') # Audio format (0x0001 == PCM) - self.f.write(b'\x02\x00') # Number of channels (2) - self.f.write(b'\x80\x3e\x00\x00') # Samplerate (16000) - self.f.write(b'\x00\x7d\x00\x00') # Byterate (32000) - self.f.write(b'\x04\x00') # Blockalign (4) - self.f.write(b'\x10\x00') # Bits per sample (16) - - # Data subchunk - self.f.write(b'data') - self.f.write(b'\xff\xff\x00\x00') # Subchunk size (65535 bytes) TODO - - self.f.flush() - - def decode(self, ss, es, data): - ptype, pdata = data - - if ptype != 'DATA': - return - - channel, sample = pdata - - if self.wrote_header == False: - self.write_wav_header() - self.wrote_header = True - - # Output the next sample to 'filename'. - # TODO: Data: first left channel, then right channel. - if self.f != None: - # TODO: This currently assumes U32 samples, and converts to S16. - s = sample >> 16 - if s >= 0x8000: - s -= 0x10000 - lo, hi = s & 0xff, (s >> 8) & 0xff - self.f.write(bytes([lo, hi])) - self.f.flush() -