def __init__(self, options=None): """Updates self.init_options dictionary with option values, creating the dictionary if it doesn't exist.""" super(sigprocbase, self).__init__() self.original_options = options if not hasattr(self, 'init_options'): self.init_options = attrdict() init_options = self.init_options if not hasattr(self, 'init_args'): self.init_args = list() init_args = self.init_args if options is None: return if isinstance(options, str): options = options.split() if isinstance(options, (list, tuple)): # put assignments in the dictionary init_options.update(option.split('=') for option in options if option.count('=') == 1) # append all others onto the list init_args.extend(option for option in options if option.count('=') != 1) elif isinstance(options, dict): init_options.update(options) else: raise ValueError("expected options to be an instance of str, tuple, list, or dict, but got %r" %(type(options).__name__,)) if init_options.has_key('serial_version'): v = int(init_options['serial_version']) self.check_serial_version(v)
def __init__(self, *_): super(Sliding, self).__init__(*_) self.signal = attrdict() # usec self.window = 25000 self.hop = self.window // 3
def __init__(self, length, add, remove): stats = builtin.attrdict(( ('num_added', 0), ('num_removed', 0), ('max_queued', 0), ('min_timestamp', None), ('max_timestamp', None), ('prev_timestamp', None), )) self._data = length, collections.deque(), add, remove, stats
def state(self): result = attrdict() STATE = self._scan('STATE') UINT = self._scan('UINT') result.statenum = atoi(UINT) mean = self.mean() result.mean = mean var = self.var() result.var = var if self._peek('GCONST', 'STATE', 'TRANSP') == 'GCONST': gconst = self.gconst() result.gconst = gconst return ('state', result)
def hmm(self): result = attrdict() if self._peek('BEGINHMM', 'HMMMACRO') == 'HMMMACRO': hmmdecl = self.hmmdecl() result.decl = hmmdecl BEGINHMM = self._scan('BEGINHMM') numstates = self.numstates() result.numstates = numstates result.states = [] while self._peek('STATE', 'TRANSP') == 'STATE': state = self.state() result.states.append(state) transp = self.transp() result.transp = transp ENDHMM = self._scan('ENDHMM') return ('HMM', result)
def __init__(self, options=None): """Updates self.init_options dictionary with option values, creating the dictionary if it doesn't exist.""" super(sigprocbase, self).__init__() self.original_options = options if not hasattr(self, 'init_options'): self.init_options = attrdict() init_options = self.init_options if not hasattr(self, 'init_args'): self.init_args = list() init_args = self.init_args if options is None: return if isinstance(options, str): options = options.split() if isinstance(options, (list, tuple)): # put assignments in the dictionary init_options.update( option.split('=') for option in options if option.count('=') == 1) # append all others onto the list init_args.extend(option for option in options if option.count('=') != 1) elif isinstance(options, dict): init_options.update(options) else: raise ValueError( "expected options to be an instance of str, tuple, list, or dict, but got %r" % (type(options).__name__, )) if init_options.has_key('serial_version'): v = int(init_options['serial_version']) self.check_serial_version(v)
def __init__(self, args=None): self.init_options = attrdict({'base': EulersNumber, 'scale': 1}) super(Log, self).__init__(args) self.logbase = pow(number(self.init_options.base), 1 / number(self.init_options.scale))
def __init__(self, r, theta): """ A simple two-pole system, with zeros at 1 and -1. Argument r is the radius to each pole, theta is the angle in radians. In the running system, you can vary r via h.set_r(new_r_value) for nonlinear behavior. >>> for y in nonlinear2pole(0.97, 0.4).process_some((.1,) * 30): ... y+=15;print '-' * int(y), int(y) ----------------- 17 ---------------------- 22 ------------------------- 25 -------------------------- 26 -------------------------- 26 ------------------------ 24 -------------------- 20 ---------------- 16 ------------ 12 -------- 8 ------ 6 ----- 5 ------ 6 -------- 8 ---------- 10 -------------- 14 ----------------- 17 -------------------- 20 --------------------- 21 ---------------------- 22 --------------------- 21 -------------------- 20 ----------------- 17 --------------- 15 ------------ 12 ---------- 10 --------- 9 --------- 9 --------- 9 ----------- 11 """ super(nonlinear2pole, self).__init__() def H(z): # print # print 'r', r, ' theta', theta zsq = z ** 2 num = zsq - 1 num2 = (z - 1) * (z + 1) # print 'num', num, num - num2 # print 'abs(num)', abs(num), 2 * math.sin(theta) #print 'z', z, abs(z), ' zsq', zsq, abs(zsq) den = zsq - 2 * r * math.cos(theta) * z + r ** 2 den2 = (z - r * pow(cmath.e, 1j*theta)) * (z - r * pow(cmath.e, -1j*theta)) # print 'den', den, den - den2 cos2theta = math.cos(2 * theta) asq = 1 - cos2theta ** 2 bsq = asq + (r - cos2theta) ** 2 assert bsq >= 0 den3 = abs(1 - r) * math.sqrt(bsq) # print 'den3', den3, abs(den) - den3 #print 'd', d #return 1 return num / den coeffs_b = 0, -1 # XXX write set_r, and use it here coeffs_a = -2 * r * math.cos(theta), r * r coeff_k = (2 * math.sin(theta)) / (1 - r) # print 'coeff_k', coeff_k, ' |H(theta)|', abs(H(pow(cmath.e, 1j*theta))) if len(coeffs_b) > 2: raise ValueError("expected coeffs_b of length 2 or less, got %d" % (len(coeffs_b),)) if len(coeffs_a) > 2: raise ValueError("expected coeffs_a of length 2 or less, got %d" % (len(coeffs_a),)) coeffs_b = tuple(islice(chain(coeffs_b, repeat(0)), 2)) coeffs_a = tuple(islice(chain(coeffs_a, repeat(0)), 2)) self.coeff_k = coeff_k self.ba = tuple(izip(coeffs_b, coeffs_a)) assert len(self.ba) == 2 self.deque = deque((0, 0)) self.data = self.coeff_k, self.ba, self.deque def senderator(coeffs_a, coeffs_b, coeff_k, signal, recipient=None): a1, a2 = coeffs_a b1, b2 = coeffs_b k = coeff_k # so we can use 'is' comparisons zero = 0 a1 = a1 or zero a2 = a2 or zero b1 = b1 or zero b2 = b2 or zero w1, w2 = reset = zero, zero hasattr = signal.hasattr result = None while True: x = yield result result = None if x is signal: if hasattr.get_recipient: result = recipient if hasattr.set_recipient: recipient = signal.set_recipient if hasattr.get_state: result = w1, w2 if hasattr.set_state: w1, w2 = signal.set_state if hasattr.reset: w1, w2 = reset continue w = k * x if a1 is not zero: w -= a1 * w1 if a2 is not zero: w -= a2 * w2 y = w if b1 is not zero: y += b1 * w1 if b2 is not zero: y += b2 * w2 w2 = w1 w1 = w if recipient is not None: recipient(y) self.signal = attrdict() self.send = senderator(coeffs_a, coeffs_b, coeff_k, self.signal).send self.send(None)
def __init__(self, coeffs_a, coeffs_b, coeff_k=1): """ Construct a canonic Type II filter that implements the (inhomogeneous) second-order difference equation: y[n] + a1 * y[n-1] + a2 * y[n-2] = k * (x[n] + b1 * x[n-1] + b2 * x[n-2]) generating the solution y[n] given input sequence x[n]: y[n] = -1 * (a1 * y[n-1] + a2 * y[n-2]) + k * (x[n] + b1 * x[n-1] + b2 * x[n-2]) The 'coeffs_a' is a sequence of zero to two IIR coefficients, 'a' in the above. The 'coeffs_b' is a sequence of zero to two FIR coefficients, 'b' in the above. In these two sequences, missing trailing coefficients are treated as having value 0. The optional 'coeff_k' argument is the overall scaling factor that defaults to one, 'k' in the above. """ super(type2stage, self).__init__() if len(coeffs_b) > 2: raise ValueError("expected coeffs_b of length 2 or less, got %d" % (len(coeffs_b),)) if len(coeffs_a) > 2: raise ValueError("expected coeffs_a of length 2 or less, got %d" % (len(coeffs_a),)) coeffs_b = tuple(islice(chain(coeffs_b, repeat(0)), 2)) coeffs_a = tuple(islice(chain(coeffs_a, repeat(0)), 2)) self.coeff_k = coeff_k self.ba = tuple(izip(coeffs_b, coeffs_a)) assert len(self.ba) == 2 self.deque = deque((0, 0)) self.data = self.coeff_k, self.ba, self.deque def senderator(coeffs_a, coeffs_b, coeff_k, signal, recipient=None): a1, a2 = coeffs_a b1, b2 = coeffs_b k = coeff_k # so we can use 'is' comparisons zero = 0 a1 = a1 or zero a2 = a2 or zero b1 = b1 or zero b2 = b2 or zero w1, w2 = reset = zero, zero hasattr = signal.hasattr result = None while True: x = yield result result = None if x is signal: if hasattr.get_recipient: result = recipient if hasattr.set_recipient: recipient = signal.set_recipient if hasattr.get_state: result = w1, w2 if hasattr.set_state: w1, w2 = signal.set_state if hasattr.reset: w1, w2 = reset continue w = k * x if a1 is not zero: w -= a1 * w1 if a2 is not zero: w -= a2 * w2 y = w if b1 is not zero: y += b1 * w1 if b2 is not zero: y += b2 * w2 w2 = w1 w1 = w if recipient is not None: recipient(y) self.signal = attrdict() self.send = senderator(coeffs_a, coeffs_b, coeff_k, self.signal).send self.send(None)
def _get_sphere_fd(fileno, file_num_bytes, filename, wave_format, filename_abs): """ Low-level reading of NIST Sphere audio data. >>> module_dir, module_name = os.path.split(__file__) >>> zero_sph = os.path.join(module_dir, 'zero.sph') >>> shorten_sph = os.path.join(module_dir, 'shorten.sph') >>> with open(zero_sph, 'rb') as audio_file: ... file_info, audio_info, wave = _get_sphere_fd(audio_file.fileno(), os.path.getsize(zero_sph), zero_sph, 'int16', os.path.abspath(zero_sph)) >>> for key in sorted(file_info): print "%-24s %r" % (key, file_info[key]) file_item_bytes 2 file_item_coding 'int16' file_sndfile_extension 'sph' file_sndfile_format '' file_sndfile_type 'pcm SPH (NIST Sphere)' >>> for key in sorted(audio_info): print "%-24s %r" % (key, audio_info[key]) audio_num_channels 2 audio_num_samples 128064 audio_sample_rate 44100 >>> print str(wave) [[ 0 -1 -3 ..., 203 211 199] [ 0 0 -3 ..., 225 225 221]] >>> with open(shorten_sph, 'rb') as audio_file: ... file_info2, audio_info2, wave2 = _get_sphere_fd(audio_file.fileno(), os.path.getsize(shorten_sph), shorten_sph, 'int16', os.path.abspath(shorten_sph)) >>> for key in sorted(file_info2): print "%-24s %r" % (key, file_info2[key]) file_item_bytes 2 file_item_coding 'int16' file_sndfile_extension 'sph' file_sndfile_format '' file_sndfile_type 'pcm,embedded-shorten-v2.00 SPH (NIST Sphere)' >>> for key in sorted(audio_info2): print "%-24s %r" % (key, audio_info2[key]) audio_num_channels 1 audio_num_samples 37120 audio_sample_rate 20000 >>> print str(wave2) [[-1 1 1 ..., -4 -8 -5]] """ assert wave_format is None or wave_format in wave_c_formats # As of 2009-04-20 see the following for NIST's underspecified # format description: # http://ftp.cwi.nl/audio/NIST-SPHERE # http://www.ldc.upenn.edu/Catalog/docs/LDC93S5/WAV_SPEC.TXT nist_1a = 'NIST_1A' header1 = read_fd_strict(fileno, 128, filename_abs) if not header1.startswith(nist_1a): raise AudioTypeError( "did not find %r in header of purported NIST Sphere file %r" % (nist_1a, filename_abs)) nist, header_size, rest = header1.split(None, 2) assert nist == nist_1a header_size = int(header_size) rest += read_fd_strict(fileno, header_size - len(header1), filename_abs) # For now, we require the following fields: # sample_count -i 128064 # sample_n_bytes -i 2 # channel_count -i 2 # sample_byte_format -s2 01 # sample_rate -i 44100 # sample_coding -s3 pcm info = builtin.attrdict() for line in cStringIO.StringIO(rest): parts = line.split() if not parts or parts[0][0] == ';': continue if parts[0] == 'end_head': break if len(parts) < 3: raise AudioTypeError( "expected at least three white-space-separated fields in NIST header line %r in file %r" % (line.strip(), filename_abs)) field_name, field_type, field_value = line.split(None, 3) #print field_name, field_type, field_value if field_type in ('-i', '-r'): field_value, _, _ = field_value.partition(';') info[field_name] = (int if field_type == '-i' else float)(field_value) elif field_type.startswith('-s'): # here we do a stricter interpretation of the spec prefix_len = len(field_name + ' ' + field_type + ' ') str_len = int(field_type[2:]) info[field_name] = line[prefix_len:prefix_len + str_len] else: raise (AudioTypeError, "unhandled field_type %r for field_name %r" % (field_type, field_name)) missing = set( ('sample_count', 'sample_n_bytes', 'channel_count', 'sample_byte_format', 'sample_rate', 'sample_coding')) - set(info) if missing: raise AudioTypeError( "missing required header fields (%s) in NIST Sphere file %r" % (', '.join(sorted(missing)), filename_abs)) # this is a blunt check against bogus data if info.sample_n_bytes > 2: raise AudioTypeError( "unhandled sample_n_bytes, %d, in NIST Sphere file %r" % (info.sample_n_bytes, filename_abs)) audio_info = builtin.attrdict((('audio_num_channels', info.channel_count), ('audio_num_samples', info.sample_count), ('audio_sample_rate', info.sample_rate))) check_positive_ints(audio_info, filename_abs) file_info = builtin.attrdict(( ('file_item_bytes', info.sample_n_bytes), ('file_item_coding', ('int' + str(8 * info.sample_n_bytes)) if info.sample_coding.lower().startswith('pcm') else info.sample_coding[:4].lower()), ('file_sndfile_extension', 'sph'), ('file_sndfile_format', ''), ('file_sndfile_type', info.sample_coding + ' SPH (NIST Sphere)'), )) check_positive_ints(file_info, filename_abs) if wave_format is not None: args = 'sph2pipe', '-p', '-f', 'raw', filename_abs stdout, stderr, cmd = process.subprocess(args) if stderr: raise onyx.ExternalError( "unexpected stderr from command '%s': '%s'" % (cmd, stderr.strip())) num_audio_bytes = audio_info.audio_num_channels * audio_info.audio_num_samples * numpy.int16( ).itemsize if len(stdout) != num_audio_bytes: raise onyx.DataFormatError( "expected %d bytes of audio data, got %d" % (num_audio_bytes, len(stdout))) wave = numpy.fromstring(stdout, dtype=numpy.int16) assert wave.shape == (audio_info.audio_num_channels * audio_info.audio_num_samples, ) # reshape it, etc; then construct a new ndarray wave = wave.reshape((-1, audio_info.audio_num_channels)).transpose() wave = numpy.array(wave, dtype=wave_numpy_formats[wave_format]) # do scaling the same way libsndfile does if wave_format == 'int32': wave <<= 16 elif wave_format in ('float32', 'float64'): wave *= (1 / (1 << 15)) assert wave.shape == (audio_info.audio_num_channels, audio_info.audio_num_samples) else: wave = None return file_info, audio_info, wave
def stats(self): length, fifo, add, remove, stats = self._data stats = builtin.attrdict(stats) stats.length = length return stats
def _get_sphere_fd(fileno, file_num_bytes, filename, wave_format, filename_abs): """ Low-level reading of NIST Sphere audio data. >>> module_dir, module_name = os.path.split(__file__) >>> zero_sph = os.path.join(module_dir, 'zero.sph') >>> shorten_sph = os.path.join(module_dir, 'shorten.sph') >>> with open(zero_sph, 'rb') as audio_file: ... file_info, audio_info, wave = _get_sphere_fd(audio_file.fileno(), os.path.getsize(zero_sph), zero_sph, 'int16', os.path.abspath(zero_sph)) >>> for key in sorted(file_info): print "%-24s %r" % (key, file_info[key]) file_item_bytes 2 file_item_coding 'int16' file_sndfile_extension 'sph' file_sndfile_format '' file_sndfile_type 'pcm SPH (NIST Sphere)' >>> for key in sorted(audio_info): print "%-24s %r" % (key, audio_info[key]) audio_num_channels 2 audio_num_samples 128064 audio_sample_rate 44100 >>> print str(wave) [[ 0 -1 -3 ..., 203 211 199] [ 0 0 -3 ..., 225 225 221]] >>> with open(shorten_sph, 'rb') as audio_file: ... file_info2, audio_info2, wave2 = _get_sphere_fd(audio_file.fileno(), os.path.getsize(shorten_sph), shorten_sph, 'int16', os.path.abspath(shorten_sph)) >>> for key in sorted(file_info2): print "%-24s %r" % (key, file_info2[key]) file_item_bytes 2 file_item_coding 'int16' file_sndfile_extension 'sph' file_sndfile_format '' file_sndfile_type 'pcm,embedded-shorten-v2.00 SPH (NIST Sphere)' >>> for key in sorted(audio_info2): print "%-24s %r" % (key, audio_info2[key]) audio_num_channels 1 audio_num_samples 37120 audio_sample_rate 20000 >>> print str(wave2) [[-1 1 1 ..., -4 -8 -5]] """ assert wave_format is None or wave_format in wave_c_formats # As of 2009-04-20 see the following for NIST's underspecified # format description: # http://ftp.cwi.nl/audio/NIST-SPHERE # http://www.ldc.upenn.edu/Catalog/docs/LDC93S5/WAV_SPEC.TXT nist_1a = 'NIST_1A' header1 = read_fd_strict(fileno, 128, filename_abs) if not header1.startswith(nist_1a): raise AudioTypeError("did not find %r in header of purported NIST Sphere file %r" % (nist_1a, filename_abs)) nist, header_size, rest = header1.split(None, 2) assert nist == nist_1a header_size = int(header_size) rest += read_fd_strict(fileno, header_size - len(header1), filename_abs) # For now, we require the following fields: # sample_count -i 128064 # sample_n_bytes -i 2 # channel_count -i 2 # sample_byte_format -s2 01 # sample_rate -i 44100 # sample_coding -s3 pcm info = builtin.attrdict() for line in cStringIO.StringIO(rest): parts = line.split() if not parts or parts[0][0] == ';': continue if parts[0] == 'end_head': break if len(parts) < 3: raise AudioTypeError("expected at least three white-space-separated fields in NIST header line %r in file %r" % (line.strip(), filename_abs)) field_name, field_type, field_value = line.split(None, 3) #print field_name, field_type, field_value if field_type in ('-i', '-r'): field_value, _, _ = field_value.partition(';') info[field_name] = (int if field_type == '-i' else float)(field_value) elif field_type.startswith('-s'): # here we do a stricter interpretation of the spec prefix_len = len(field_name + ' ' + field_type + ' ') str_len = int(field_type[2:]) info[field_name] = line[prefix_len:prefix_len+str_len] else: raise (AudioTypeError, "unhandled field_type %r for field_name %r" % (field_type, field_name)) missing = set(('sample_count', 'sample_n_bytes', 'channel_count', 'sample_byte_format', 'sample_rate', 'sample_coding')) - set(info) if missing: raise AudioTypeError("missing required header fields (%s) in NIST Sphere file %r" % (', '.join(sorted(missing)), filename_abs)) # this is a blunt check against bogus data if info.sample_n_bytes > 2: raise AudioTypeError("unhandled sample_n_bytes, %d, in NIST Sphere file %r" % (info.sample_n_bytes, filename_abs)) audio_info = builtin.attrdict((('audio_num_channels', info.channel_count), ('audio_num_samples', info.sample_count), ('audio_sample_rate', info.sample_rate))) check_positive_ints(audio_info, filename_abs) file_info = builtin.attrdict((('file_item_bytes', info.sample_n_bytes), ('file_item_coding', ('int' + str(8*info.sample_n_bytes)) if info.sample_coding.lower().startswith('pcm') else info.sample_coding[:4].lower()), ('file_sndfile_extension', 'sph'), ('file_sndfile_format', ''), ('file_sndfile_type', info.sample_coding + ' SPH (NIST Sphere)'), )) check_positive_ints(file_info, filename_abs) if wave_format is not None: args = 'sph2pipe', '-p', '-f', 'raw', filename_abs stdout, stderr, cmd = process.subprocess(args) if stderr: raise onyx.ExternalError("unexpected stderr from command '%s': '%s'" % (cmd, stderr.strip())) num_audio_bytes = audio_info.audio_num_channels * audio_info.audio_num_samples * numpy.int16().itemsize if len(stdout) != num_audio_bytes: raise onyx.DataFormatError("expected %d bytes of audio data, got %d" % (num_audio_bytes, len(stdout))) wave = numpy.fromstring(stdout, dtype=numpy.int16) assert wave.shape == (audio_info.audio_num_channels * audio_info.audio_num_samples,) # reshape it, etc; then construct a new ndarray wave = wave.reshape((-1, audio_info.audio_num_channels)).transpose() wave = numpy.array(wave, dtype=wave_numpy_formats[wave_format]) # do scaling the same way libsndfile does if wave_format == 'int32': wave <<= 16 elif wave_format in ('float32', 'float64'): wave *= (1 / (1 << 15)) assert wave.shape == (audio_info.audio_num_channels, audio_info.audio_num_samples) else: wave = None return file_info, audio_info, wave
def _get_audio_fd(fd, file_num_bytes, name, wave_format, full_name=None, is_mpeg=None): """ Low-level reading of audio from libsndfile and mpg123 audio libraries. Test a correct error from libsndfile that sph2pipe does not catch; this is a small exercise of the error handling chain >>> module_dir, module_name = os.path.split(__file__) >>> problem_sph = os.path.join(module_dir, 'problem.sph') >>> with open(problem_sph, 'rb') as infile: ... info3 = _get_audio_fd(infile.fileno(), os.path.getsize(problem_sph), problem_sph, None, problem_sph, False) #doctest: +ELLIPSIS Traceback (most recent call last): ... AudioTypeError: .../cpp/liveaudio/sndfilewrap.c:... get_sndfile(): unexpected NULL from sf_open_fd: maybe not a valid sound file: '...problem.sph': SFC_GET_LOG_INFO: Length : 1104 psf->bytewidth (4) != bytes (2) Also test that libsndfile notices that it cannot deal with shorten encoding; also a small exercise of the error handling chain >>> shorten_sph = os.path.join(module_dir, 'shorten.sph') >>> with open(shorten_sph, 'rb') as infile: ... info3 = _get_audio_fd(infile.fileno(), os.path.getsize(shorten_sph), shorten_sph, None, shorten_sph, False) #doctest: +ELLIPSIS Traceback (most recent call last): ... AudioTypeError: .../cpp/liveaudio/sndfilewrap.c:... get_sndfile(): unexpected NULL from sf_open_fd: maybe not a valid sound file: '...shorten.sph': SFC_GET_LOG_INFO: Length : 28357 *** Unknown encoding : pcm,embedded-shorten-v2.00 """ assert fd >= 0, str(fd) assert wave_format is None or wave_format in wave_c_formats getter = _sndfilewrap_get_audio_fd if not is_mpeg else _mpg123wrap_get_audio_fd with getter(fd, name, wave_format) as ptrs: # get the returned strings info_str, casual, _ = tuple(ptr.value for ptr in ptrs) # populate info audio_info = builtin.attrdict((key, value) for key, value in parse_key_value(info_str) if key.startswith('audio')) check_positive_ints(audio_info, name) file_info = builtin.attrdict((key, value) for key, value in parse_key_value(info_str) if key.startswith('file')) file_info.file_sndfile_type = casual check_positive_ints(file_info, name, exclusions=('file_item_bytes',)) # deal with the wave data at ptrs[-1], if any wave_ptr = ptrs[-1] assert (wave_ptr.value is None) == (wave_format is None) if wave_format is not None: # cast the void** data in wave_ptr to a C-array of the correct # length; then have Numpy use that data in a ctypeslib.as_array; get # a reshaped and transposed view (cheap); then copy to a bona-fide # Numpy array from numpy import ctypeslib # create a C type for the returned data c_array_t = wave_c_formats[wave_format] * audio_info.audio_num_samples * audio_info.audio_num_channels # use the returned memory wave = ctypeslib.as_array(cast(wave_ptr, POINTER(c_array_t)).contents) # reshape it, etc; then copy to a new ndarray wave = wave.reshape((-1, audio_info.audio_num_channels)).transpose().copy() # at this point we're done with the ptrs assert wave.shape == (audio_info.audio_num_channels, audio_info.audio_num_samples) else: wave = None return file_info, audio_info, wave
def __init__(self, instream, stream_type=None, stream_version=None, no_stream_options=False, header_only=False): if not isinstance(instream, YamldataGenerator): instream = YamldataGenerator(instream) have_filename = hasattr(instream, 'current_filename') if have_filename: self.current_filename = instream.current_filename stream_name = (self.current_filename if have_filename else "Yamldata stream") doc = instream.next() if (not hasattr(doc, '__len__')) or len(doc) == 0: raise ValueError("no header found in %s; are you sure this is a Yamldata source?" % stream_name) # attrdict of all the Onyx headers try: header = attrdict(doc[0]) except: raise ValueError("bad header structure in %s: [%s] - are you sure this is a Yamldata source?" % (stream_name, doc[0])) if len(doc) > 2: raise ValueError("bad document structure in %s, expected 1 or 2 sub-parts, got %d" % (stream_name, len(doc))) # print doc if header_only: if len(doc) != 1: raise ValueError("bad document structure in %s, expected only a header" % stream_name) data = None else: if len(doc) != 2: raise ValueError("bad document structure in %s, expected both a header and a body" % stream_name) data = doc[1] missing_headers = frozenset(self.prefix_header_names(self.required_headers)) - frozenset(header) if missing_headers: raise ValueError("missing the following required headers in %s: %s" % (stream_name, (' '.join(repr(header) for header in sorted(missing_headers))))) invalid_headers = frozenset(header) - frozenset(self.prefix_header_names(self.valid_headers)) if invalid_headers: raise ValueError("unexpected headers in %s: %s" % (stream_name, (' '.join(repr(header) for header in sorted(invalid_headers))))) for base_name, prefixed_name in _izip(self.valid_headers, self.prefix_header_names(self.valid_headers)): if prefixed_name in header: self[base_name] = header[prefixed_name] # check the fields if self.meta_version != self.VERSION: raise ValueError("unexpected meta_version in %s: expected %s, got %s" % (stream_name, self.VERSION, self.meta_version)) if stream_type is not None and self.stream_type != stream_type: raise ValueError("unexpected stream_type in %s: expected %r, got %r" % (stream_name, stream_type, self.stream_type)) if stream_version is not None and self.stream_version != stream_version: raise ValueError("unexpected stream_version in %s: expected %s, got %s" % (stream_name, repr(stream_version), repr(self.stream_version))) if no_stream_options and self.hasattr.stream_options: raise ValueError("unexpected presence of stream_options in header: %r" % (self.stream_options,)) self.current_line_number = 4 + (0 if no_stream_options else 1) def itr(): for line in data: self.current_line_contents = line self.current_line_number += 1 # Note: PyYAML will implicitly convert tokens which # match certain regexps to their "natural" types. The # effect is that if a line has only a single token # which can be converted to float or int, it will be # so converted. Here we detect that and convert back # to a tuple with one string to make our output consistent. if type(line) != str: parts = (str(line),) else: parts = line.split() if not parts: continue yield parts self._next = itr().next
def _get_audio_fd(fd, file_num_bytes, name, wave_format, full_name=None, is_mpeg=None): """ Low-level reading of audio from libsndfile and mpg123 audio libraries. Test a correct error from libsndfile that sph2pipe does not catch; this is a small exercise of the error handling chain >>> module_dir, module_name = os.path.split(__file__) >>> problem_sph = os.path.join(module_dir, 'problem.sph') >>> with open(problem_sph, 'rb') as infile: ... info3 = _get_audio_fd(infile.fileno(), os.path.getsize(problem_sph), problem_sph, None, problem_sph, False) #doctest: +ELLIPSIS Traceback (most recent call last): ... AudioTypeError: .../cpp/liveaudio/sndfilewrap.c:... get_sndfile(): unexpected NULL from sf_open_fd: maybe not a valid sound file: '...problem.sph': SFC_GET_LOG_INFO: Length : 1104 psf->bytewidth (4) != bytes (2) Also test that libsndfile notices that it cannot deal with shorten encoding; also a small exercise of the error handling chain >>> shorten_sph = os.path.join(module_dir, 'shorten.sph') >>> with open(shorten_sph, 'rb') as infile: ... info3 = _get_audio_fd(infile.fileno(), os.path.getsize(shorten_sph), shorten_sph, None, shorten_sph, False) #doctest: +ELLIPSIS Traceback (most recent call last): ... AudioTypeError: .../cpp/liveaudio/sndfilewrap.c:... get_sndfile(): unexpected NULL from sf_open_fd: maybe not a valid sound file: '...shorten.sph': SFC_GET_LOG_INFO: Length : 28357 *** Unknown encoding : pcm,embedded-shorten-v2.00 """ assert fd >= 0, str(fd) assert wave_format is None or wave_format in wave_c_formats getter = _sndfilewrap_get_audio_fd if not is_mpeg else _mpg123wrap_get_audio_fd with getter(fd, name, wave_format) as ptrs: # get the returned strings info_str, casual, _ = tuple(ptr.value for ptr in ptrs) # populate info audio_info = builtin.attrdict( (key, value) for key, value in parse_key_value(info_str) if key.startswith('audio')) check_positive_ints(audio_info, name) file_info = builtin.attrdict( (key, value) for key, value in parse_key_value(info_str) if key.startswith('file')) file_info.file_sndfile_type = casual check_positive_ints(file_info, name, exclusions=('file_item_bytes', )) # deal with the wave data at ptrs[-1], if any wave_ptr = ptrs[-1] assert (wave_ptr.value is None) == (wave_format is None) if wave_format is not None: # cast the void** data in wave_ptr to a C-array of the correct # length; then have Numpy use that data in a ctypeslib.as_array; get # a reshaped and transposed view (cheap); then copy to a bona-fide # Numpy array from numpy import ctypeslib # create a C type for the returned data c_array_t = wave_c_formats[ wave_format] * audio_info.audio_num_samples * audio_info.audio_num_channels # use the returned memory wave = ctypeslib.as_array( cast(wave_ptr, POINTER(c_array_t)).contents) # reshape it, etc; then copy to a new ndarray wave = wave.reshape( (-1, audio_info.audio_num_channels)).transpose().copy() # at this point we're done with the ptrs assert wave.shape == (audio_info.audio_num_channels, audio_info.audio_num_samples) else: wave = None return file_info, audio_info, wave