def tags(file, order): while True: reader = BitstreamReader(file, order) # read all the tags in an IFD tag_count = reader.read(16) sub_reader = reader.substream(tag_count * 12) next_ifd = reader.read(32) for i in range(tag_count): (tag_code, tag_datatype, tag_value_count) = sub_reader.parse("16u 16u 32u") if tag_datatype == 1: # BYTE type tag_struct = "8u" * tag_value_count elif tag_datatype == 3: # SHORT type tag_struct = "16u" * tag_value_count elif tag_datatype == 4: # LONG type tag_struct = "32u" * tag_value_count else: # all other types tag_struct = "4b" if format_size(tag_struct) <= 32: yield (tag_code, sub_reader.parse(tag_struct)) sub_reader.skip(32 - format_size(tag_struct)) else: offset = sub_reader.read(32) file.seek(offset, 0) yield (tag_code, BitstreamReader(file, order).parse(tag_struct)) if next_ifd != 0: file.seek(next_ifd, 0) else: break
def aiff_header(sample_rate, channels, bits_per_sample, total_pcm_frames): """given a set of integer stream attributes, returns header string of everything before an AIFF's PCM data may raise ValueError if the total size of the file is too large""" from audiotools.bitstream import (BitstreamRecorder, format_size) header = BitstreamRecorder(False) data_size = (bits_per_sample // 8) * channels * total_pcm_frames total_size = ((format_size("4b" + "4b 32u" + "16u 32u 16u 1u 15u 64U" + "4b 32u 32u 32u") // 8) + data_size + (data_size % 2)) if total_size < (2**32): header.build("4b 32u 4b", (b"FORM", total_size, b"AIFF")) header.build("4b 32u", (b"COMM", 0x12)) header.build("16u 32u 16u", (channels, total_pcm_frames, bits_per_sample)) build_ieee_extended(header, sample_rate) header.build("4b 32u 32u 32u", (b"SSND", data_size + 8, 0, 0)) return header.data() else: raise ValueError("total size too large for aiff file")
def aiff_header(sample_rate, channels, bits_per_sample, total_pcm_frames): """given a set of integer stream attributes, returns header string of everything before an AIFF's PCM data may raise ValueError if the total size of the file is too large""" from audiotools.bitstream import (BitstreamRecorder, format_size) header = BitstreamRecorder(False) data_size = (bits_per_sample // 8) * channels * total_pcm_frames total_size = ((format_size("4b" + "4b 32u" + "16u 32u 16u 1u 15u 64U" + "4b 32u 32u 32u") // 8) + data_size + (data_size % 2)) if total_size < (2 ** 32): header.build("4b 32u 4b", (b"FORM", total_size, b"AIFF")) header.build("4b 32u", (b"COMM", 0x12)) header.build("16u 32u 16u", (channels, total_pcm_frames, bits_per_sample)) build_ieee_extended(header, sample_rate) header.build("4b 32u 32u 32u", (b"SSND", data_size + 8, 0, 0)) return header.data() else: raise ValueError("total size too large for aiff file")
def write_wave_header(writer, pcmreader, total_frames, wave_footer_len): avg_bytes_per_second = pcmreader.sample_rate * pcmreader.channels * (pcmreader.bits_per_sample / 8) block_align = pcmreader.channels * (pcmreader.bits_per_sample / 8) total_size = 4 * 3 #'RIFF' + size + 'WAVE' total_size += 4 * 2 #'fmt ' + size if (pcmreader.channels <= 2) and (pcmreader.bits_per_sample <= 16): # classic fmt chunk fmt = "16u 16u 32u 32u 16u 16u" fmt_fields = ( 1, # compression code pcmreader.channels, pcmreader.sample_rate, avg_bytes_per_second, block_align, pcmreader.bits_per_sample, ) else: # extended fmt chunk fmt = "16u 16u 32u 32u 16u 16u" + "16u 16u 32u 16b" fmt_fields = ( 0xFFFE, # compression code pcmreader.channels, pcmreader.sample_rate, avg_bytes_per_second, block_align, pcmreader.bits_per_sample, 22, # CB size pcmreader.bits_per_sample, pcmreader.channel_mask, "\x01\x00\x00\x00\x00\x00\x10\x00" + "\x80\x00\x00\xaa\x00\x38\x9b\x71", # sub format ) total_size += format_size(fmt) / 8 total_size += 4 * 2 #'data' + size data_size = total_frames * pcmreader.channels * (pcmreader.bits_per_sample / 8) total_size += data_size total_size += wave_footer_len writer.build( "4b 32u 4b 4b 32u" + fmt + "4b 32u", (("RIFF", total_size - 8, "WAVE", "fmt ", format_size(fmt) / 8) + fmt_fields + ("data", data_size)), )
def wave_header(sample_rate, channels, channel_mask, bits_per_sample, total_pcm_frames): """given a set of integer stream attributes, returns header string of everything before a RIFF WAVE's PCM data may raise ValueError if the total size of the file is too large""" from audiotools.bitstream import (BitstreamRecorder, format_size) assert(isinstance(sample_rate, int)) assert(isinstance(channels, int)) assert(isinstance(channel_mask, int)) assert(isinstance(bits_per_sample, int)) assert(isinstance(total_pcm_frames, int) or isinstance(total_pcm_frames, long)) header = BitstreamRecorder(True) avg_bytes_per_second = sample_rate * channels * (bits_per_sample // 8) block_align = channels * (bits_per_sample // 8) # build a regular or extended fmt chunk # based on the reader's attributes if ((channels <= 2) and (bits_per_sample <= 16)): fmt = "16u 16u 32u 32u 16u 16u" fmt_fields = (1, # compression code channels, sample_rate, avg_bytes_per_second, block_align, bits_per_sample) else: if channel_mask == 0: channel_mask = {1: 0x4, 2: 0x3, 3: 0x7, 4: 0x33, 5: 0x37, 6: 0x3F}.get(channels, 0) fmt = "16u 16u 32u 32u 16u 16u" + "16u 16u 32u 16b" fmt_fields = (0xFFFE, # compression code channels, sample_rate, avg_bytes_per_second, block_align, bits_per_sample, 22, # CB size bits_per_sample, channel_mask, b'\x01\x00\x00\x00\x00\x00\x10\x00' + b'\x80\x00\x00\xaa\x00\x38\x9b\x71' # sub format ) data_size = (bits_per_sample // 8) * channels * total_pcm_frames total_size = ((format_size("4b" + "4b 32u" + fmt + "4b 32u") // 8) + data_size + (data_size % 2)) if total_size < (2 ** 32): header.build("4b 32u 4b", (b"RIFF", total_size, b"WAVE")) header.build("4b 32u", (b"fmt ", format_size(fmt) // 8)) header.build(fmt, fmt_fields) header.build("4b 32u", (b"data", data_size)) return header.data() else: raise ValueError("total size too large for wave file")