static void dsf_stream_decode(struct decoder *decoder, struct input_stream *is) { struct dsf_metadata metadata = { .sample_rate = 0, .channels = 0, }; /* check if it is a proper DSF file */ if (!dsf_read_metadata(decoder, is, &metadata)) return; GError *error = NULL; struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } /* success: file was recognized */ decoder_initialized(decoder, &audio_format, false, -1); if (!dsf_decode_chunk(decoder, is, metadata.channels, metadata.chunk_size, metadata.bitreverse)) return; } static bool dsf_scan_stream(struct input_stream *is, G_GNUC_UNUSED const struct tag_handler *handler, G_GNUC_UNUSED void *handler_ctx) { struct dsf_metadata metadata = { .sample_rate = 0, .channels = 0, }; /* check DSF metadata */ if (!dsf_read_metadata(NULL, is, &metadata)) return false; struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, NULL)) /* refuse to parse files which we cannot play anyway */ return false; return true; } static const char *const dsf_suffixes[] = { "dsf", NULL }; static const char *const dsf_mime_types[] = { "application/x-dsf", NULL }; const struct decoder_plugin dsf_decoder_plugin = { .name = "dsf", .stream_decode = dsf_stream_decode, .scan_stream = dsf_scan_stream, .suffixes = dsf_suffixes, .mime_types = dsf_mime_types, };
static void dsdiff_stream_decode(struct decoder *decoder, struct input_stream *is) { struct dsdiff_metadata metadata = { .sample_rate = 0, .channels = 0, }; struct dsdiff_chunk_header chunk_header; /* First see if it is is a DFF file */ if (!dsdiff_read_metadata(decoder, is, &metadata, &chunk_header)) { /* It was not a DFF file, now check if it is a DSF file */ if (!dsf_read_metadata(decoder, is, &metadata)) return; } GError *error = NULL; struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } /* success: file was recognized */ decoder_initialized(decoder, &audio_format, false, -1); if (!metadata.fileisdff) { uint64_t chunk_size = metadata.chunk_size; if (!dsdiff_decode_chunk(decoder, is, metadata.channels, chunk_size, metadata.fileisdff, metadata.bitreverse)) return; } else { /* every iteration of the following loop decodes one "DSD" chunk from a DFF file */ while (true) { uint64_t chunk_size = dsdiff_chunk_size(&chunk_header); if (dsdiff_id_equals(&chunk_header.id, "DSD ")) { if (!dsdiff_decode_chunk(decoder, is, metadata.channels, chunk_size, metadata.fileisdff, /* Set bitreverse to false for DFF files */ false)) break; } else { /* ignore other chunks */ if (!dsdiff_skip(decoder, is, chunk_size)) break; } /* read next chunk header; the first one was read by dsdiff_read_metadata() */ if (!dsdiff_read_chunk_header(decoder, is, &chunk_header)) break; } } } static bool dsdiff_scan_stream(struct input_stream *is, G_GNUC_UNUSED const struct tag_handler *handler, G_GNUC_UNUSED void *handler_ctx) { struct dsdiff_metadata metadata = { .sample_rate = 0, .channels = 0, }; struct dsdiff_chunk_header chunk_header; /* First check for DFF metadata */ if (!dsdiff_read_metadata(NULL, is, &metadata, &chunk_header)) { /* It was not an DFF file, now check for DSF metadata */ if (!dsf_read_metadata(NULL, is, &metadata)) return false; } struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8, SAMPLE_FORMAT_DSD, metadata.channels, NULL)) /* refuse to parse files which we cannot play anyway */ return false; /* no total time estimate, no tags implemented yet */ return true; } static const char *const dsdiff_suffixes[] = { "dff", "dsf", NULL }; static const char *const dsdiff_mime_types[] = { "application/x-dff", "application/x-dsf", NULL }; const struct decoder_plugin dsdiff_decoder_plugin = { .name = "dsdiff", .init = dsdiff_init, .stream_decode = dsdiff_stream_decode, .scan_stream = dsdiff_scan_stream, .suffixes = dsdiff_suffixes, .mime_types = dsdiff_mime_types, };