def write_adsc(fname: str, data: np.array, header: dict = {}): """Write adsc format.""" if 'SIZE1' not in header and 'SIZE2' not in header: dim2, dim1 = data.shape header['SIZE1'] = dim1 header['SIZE2'] = dim2 out = b'{\n' for key in header: out += '{:}={:};\n'.format(key, header[key]).encode() if 'HEADER_BYTES' in header: pad = int(header['HEADER_BYTES']) - len(out) - 2 else: # hsize = ((len(out) + 23) // 512 + 1) * 512 hsize = (len(out) + 533) & ~(512 - 1) out += f'HEADER_BYTES={hsize:d};\n'.encode() pad = hsize - len(out) - 2 out += b'}' + (pad + 1) * b'\x00' assert len(out) % 512 == 0, 'Header is not multiple of 512' # NOTE: XDS can handle only "SMV" images of TYPE=unsigned_short. dtype = np.uint16 data = np.round(data, 0).astype( dtype, copy=False ) # copy=False ensures that no copy is made if dtype is already satisfied if swap_needed(header): data.byteswap(True) with open(fname, 'wb') as outf: outf.write(out) outf.write(data.tostring())
def write_adsc(fname: str, data: np.array, header: dict = {}): """ Write adsc format """ out = b'{\n' for key in header: out += "{:}={:};\n".format(key, header[key]).encode() if "HEADER_BYTES" in header: pad = int(header["HEADER_BYTES"]) - len(out) - 2 else: # hsize = ((len(out) + 23) // 512 + 1) * 512 hsize = (len(out) + 533) & ~(512 - 1) out += "HEADER_BYTES={:d};\n".format(hsize).encode() pad = hsize - len(out) - 2 out += b"}" + (pad + 1) * b'\x00' assert len(out) % 512 == 0, "Header is not multiple of 512" # NOTE: XDS can handle only "SMV" images of TYPE=unsigned_short. dtype = np.uint16 data = np.round(data, 0).astype( dtype, copy=False ) # copy=False ensures that no copy is made if dtype is already satisfied if swap_needed(header): data.byteswap(True) with open(fname, "wb") as outf: outf.write(out) outf.write(data.tostring())
def write_wav(handle: T.IO[bytes], rate: int, data: np.array) -> None: """Write a numpy array of samples as a single uncompressed WAV file. To write multiple-channels, use a 2-D array of shape (Nsamples, Nchannels). The bits-per-sample and PCM/float will be determined by the data-type. :param handle: handle to write the file to :param rate: the sample rate in samples/sec :param data: a 1D or 2D numpy array of either integer or float data-type """ dkind = data.dtype.kind if not (dkind == "i" or dkind == "f" or (dkind == "u" and data.dtype.itemsize == 1)): raise ValueError(f"unsupported data type {data.dtype!r}") header_data = b"RIFF" header_data += b"\x00\x00\x00\x00" header_data += b"WAVE" # fmt chunk header_data += b"fmt " if dkind == "f": format_tag = WAVE_FORMAT_IEEE_FLOAT else: format_tag = WAVE_FORMAT_PCM if data.ndim == 1: channels = 1 else: channels = data.shape[1] bit_depth = data.dtype.itemsize * 8 bytes_per_second = rate * (bit_depth // 8) * channels block_align = channels * (bit_depth // 8) fmt_chunk_data = struct.pack( "<HHIIHH", format_tag, channels, rate, bytes_per_second, block_align, bit_depth, ) if dkind not in "iu": # add cbSize field for non-PCM files fmt_chunk_data += b"\x00\x00" header_data += struct.pack("<I", len(fmt_chunk_data)) header_data += fmt_chunk_data # fact chunk (non-PCM files) if dkind not in "iu": header_data += b"fact" header_data += struct.pack("<II", 4, data.shape[0]) # check data size (needs to be immediately before the data chunk) if ((len(header_data) - 4 - 4) + (4 + 4 + data.nbytes)) > 0xFFFFFFFF: raise ValueError("data exceeds wave file size limit") handle.write(header_data) handle.write(b"data") handle.write(struct.pack("<I", data.nbytes)) if data.dtype.byteorder == ">" or (data.dtype.byteorder == "=" and sys.byteorder == "big"): data = data.byteswap() handle.write(data.ravel().view("b").data) # Determine file size and place it at start of the file. size = handle.tell() handle.seek(4) handle.write(struct.pack("<I", size - 8))