/** * Read and parse a "SND" chunk inside "PROP". */ static bool dsdiff_read_prop_snd(struct decoder *decoder, struct input_stream *is, struct dsdiff_metadata *metadata, goffset end_offset) { struct dsdiff_chunk_header header; while ((goffset)(is->offset + sizeof(header)) <= end_offset) { if (!dsdiff_read_chunk_header(decoder, is, &header)) return false; goffset chunk_end_offset = is->offset + dsdiff_chunk_size(&header); if (chunk_end_offset > end_offset) return false; if (dsdiff_id_equals(&header.id, "FS ")) { uint32_t sample_rate; if (!dsdiff_read_payload(decoder, is, &header, &sample_rate, sizeof(sample_rate))) return false; metadata->sample_rate = GUINT32_FROM_BE(sample_rate); } else if (dsdiff_id_equals(&header.id, "CHNL")) { uint16_t channels; if (dsdiff_chunk_size(&header) < sizeof(channels) || !dsdiff_read(decoder, is, &channels, sizeof(channels)) || !dsdiff_skip_to(decoder, is, chunk_end_offset)) return false; metadata->channels = GUINT16_FROM_BE(channels); } else if (dsdiff_id_equals(&header.id, "CMPR")) { struct dsdiff_id type; if (dsdiff_chunk_size(&header) < sizeof(type) || !dsdiff_read(decoder, is, &type, sizeof(type)) || !dsdiff_skip_to(decoder, is, chunk_end_offset)) return false; if (!dsdiff_id_equals(&type, "DSD ")) /* only uncompressed DSD audio data is implemented */ return false; } else { /* ignore unknown chunk */ if (!dsdiff_skip_to(decoder, is, chunk_end_offset)) return false; } } return is->offset == end_offset; }
dsdbuffer *dsd_read(dsdfile *file) { if (!file) return NULL; if (file->type == DSF) return dsf_read(file); if (file->type == DSDIFF) return dsdiff_read(file); return NULL; }
/** * Read and parse all metadata chunks at the beginning. Stop when the * first "DSD" chunk is seen, and return its header in the * "chunk_header" parameter. */ static bool dsdiff_read_metadata(struct decoder *decoder, struct input_stream *is, struct dsdiff_metadata *metadata, struct dsdiff_chunk_header *chunk_header) { struct dsdiff_header header; if (!dsdiff_read(decoder, is, &header, sizeof(header)) || !dsdiff_id_equals(&header.id, "FRM8") || !dsdiff_id_equals(&header.format, "DSD ")) return false; while (true) { if (!dsdiff_read_chunk_header(decoder, is, chunk_header)) return false; if (dsdiff_id_equals(&chunk_header->id, "PROP")) { if (!dsdiff_read_prop(decoder, is, metadata, chunk_header)) return false; } else if (dsdiff_id_equals(&chunk_header->id, "DSD ")) { /* done with metadata, mark as DFF */ metadata->fileisdff = true; return true; } else { /* ignore unknown chunk */ uint64_t chunk_size; chunk_size = dsdiff_chunk_size(chunk_header); goffset chunk_end_offset = is->offset + chunk_size; if (!dsdiff_skip_to(decoder, is, chunk_end_offset)) return false; } } }
/** * Read and parse all needed metadata chunks for DSF files. */ static bool dsf_read_metadata(struct decoder *decoder, struct input_stream *is, struct dsdiff_metadata *metadata) { /* Reset to beginning of the stream */ if (!dsdiff_skip_to(decoder, is, 0)) return false; uint64_t chunk_size; struct dsf_header dsf_header; if (!dsdiff_read(decoder, is, &dsf_header, sizeof(dsf_header)) || !dsdiff_id_equals(&dsf_header.id, "DSD ")) return false; chunk_size = (((uint64_t)GUINT32_FROM_LE(dsf_header.size_high)) << 32) | ((uint64_t)GUINT32_FROM_LE(dsf_header.size_low)); if (sizeof(dsf_header) != chunk_size) return false; /* Read the 'fmt ' chunk of the DSF file */ struct dsf_fmt_chunk dsf_fmt_chunk; if (!dsdiff_read(decoder, is, &dsf_fmt_chunk, sizeof(dsf_fmt_chunk)) || !dsdiff_id_equals(&dsf_fmt_chunk.id, "fmt ")) return false; uint64_t fmt_chunk_size; fmt_chunk_size = (((uint64_t)GUINT32_FROM_LE(dsf_fmt_chunk.size_high)) << 32) | ((uint64_t)GUINT32_FROM_LE(dsf_fmt_chunk.size_low)); if (fmt_chunk_size != sizeof(dsf_fmt_chunk)) return false; uint32_t samplefreq = (uint32_t)GUINT32_FROM_LE(dsf_fmt_chunk.sample_freq); /* For now, only support version 1 of the standard, DSD raw stereo files with a sample freq of 2822400 Hz */ if (dsf_fmt_chunk.version != 1 || dsf_fmt_chunk.formatid != 0 || dsf_fmt_chunk.channeltype != 2 || dsf_fmt_chunk.channelnum != 2 || samplefreq != 2822400) return false; uint32_t chblksize = (uint32_t)GUINT32_FROM_LE(dsf_fmt_chunk.block_size); /* According to the spec block size should always be 4096 */ if (chblksize != 4096) return false; /* Read the 'data' chunk of the DSF file */ struct dsf_data_chunk data_chunk; if (!dsdiff_read(decoder, is, &data_chunk, sizeof(data_chunk)) || !dsdiff_id_equals(&data_chunk.id, "data")) return false; /* Data size of DSF files are padded to multiple of 4096, we use the actual data size as chunk size */ uint64_t data_size; data_size = (((uint64_t)GUINT32_FROM_LE(data_chunk.size_high)) << 32) | ((uint64_t)GUINT32_FROM_LE(data_chunk.size_low)); data_size -= sizeof(data_chunk); metadata->chunk_size = data_size; metadata->channels = (unsigned) dsf_fmt_chunk.channelnum; metadata->sample_rate = samplefreq; /* Check bits per sample format, determine if bitreverse is needed */ metadata->bitreverse = dsf_fmt_chunk.bitssample == 1 ? true : false; metadata->fileisdff = false; return true; }
static bool dsdiff_read_chunk_header(struct decoder *decoder, struct input_stream *is, struct dsdiff_chunk_header *header) { return dsdiff_read(decoder, is, header, sizeof(*header)); }
static bool dsdiff_read_id(struct decoder *decoder, struct input_stream *is, struct dsdiff_id *id) { return dsdiff_read(decoder, is, id, sizeof(*id)); }