# Copyright (C) 2017 Boris Pruessmann # # 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. """Read and write DSF audio stream information and tags.""" import sys import struct from io import BytesIO from mutagen import FileType, StreamInfo from mutagen._util import cdata, MutagenError, loadfile, \ convert_error, reraise, endswith from mutagen.id3 import ID3 from mutagen.id3._util import ID3NoHeaderError, error as ID3Error __all__ = ["DSF", "Open", "delete"] class error(MutagenError): pass class DSFChunk(object): """A generic chunk of a DSFFile.""" chunk_offset = 0 chunk_header = " " chunk_size = -1 def __init__(self, fileobj, create=False): self.fileobj = fileobj if not create: self.chunk_offset = fileobj.tell() self.load() def load(self): raise NotImplementedError def write(self): raise NotImplementedError class DSDChunk(DSFChunk): """Represents the first chunk of a DSF file""" CHUNK_SIZE = 28 total_size = 0 offset_metdata_chunk = 0 def __init__(self, fileobj, create=False): super(DSDChunk, self).__init__(fileobj, create) if create: self.chunk_header = b"DSD " self.chunk_size = DSDChunk.CHUNK_SIZE def load(self): data = self.fileobj.read(DSDChunk.CHUNK_SIZE) if len(data) != DSDChunk.CHUNK_SIZE: raise error("DSF chunk truncated") self.chunk_header = data[0:4] if self.chunk_header != b"DSD ": raise error("DSF dsd header not found") self.chunk_size = cdata.ulonglong_le(data[4:12]) if self.chunk_size != DSDChunk.CHUNK_SIZE: raise error("DSF dsd header size mismatch") self.total_size = cdata.ulonglong_le(data[12:20]) self.offset_metdata_chunk = cdata.ulonglong_le(data[20:28]) def write(self): f = BytesIO() f.write(self.chunk_header) f.write(struct.pack("