diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index b9338f16d68..19281f68a47 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -25,6 +25,7 @@ project "formats" MAME_DIR .. "src/lib/util", MAME_DIR .. "3rdparty", GEN_DIR, + ext_includedir("flac"), ext_includedir("zlib"), } @@ -37,6 +38,8 @@ project "formats" MAME_DIR .. "src/lib/formats/cassimg.cpp", MAME_DIR .. "src/lib/formats/cassimg.h", + MAME_DIR .. "src/lib/formats/flacfile.cpp", + MAME_DIR .. "src/lib/formats/flacfile.h", MAME_DIR .. "src/lib/formats/wavfile.cpp", MAME_DIR .. "src/lib/formats/wavfile.h", diff --git a/src/lib/formats/cassimg.h b/src/lib/formats/cassimg.h index d96139cfa19..9714e8e223b 100644 --- a/src/lib/formats/cassimg.h +++ b/src/lib/formats/cassimg.h @@ -136,6 +136,7 @@ public: uint8_t image_read_byte(uint64_t offset); void image_write(const void *buffer, uint64_t offset, size_t length); uint64_t image_size(); + util::random_read_write::ptr &get_raw_cassette_image() { return m_io; } // waveform accesses error get_samples(int channel, @@ -191,6 +192,7 @@ public: // builtin formats static const Format wavfile_format; + static const Format flacfile_format; private: struct manipulation_ranges; @@ -224,7 +226,8 @@ private: #define CASSETTE_FORMATLIST_START(name) \ const cassette_image::Format *const name[] = \ { \ - &cassette_image::wavfile_format, + &cassette_image::wavfile_format, \ + &cassette_image::flacfile_format, #define CASSETTE_FORMAT(name) \ &(name), #define CASSETTE_FORMATLIST_END \ diff --git a/src/lib/formats/flacfile.cpp b/src/lib/formats/flacfile.cpp new file mode 100644 index 00000000000..0e34122ada3 --- /dev/null +++ b/src/lib/formats/flacfile.cpp @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/********************************************************************* + + flacfile.cpp + + Format code for flac files. + +*********************************************************************/ + +#include "flacfile.h" + +#include "flac.h" + +#include +#include + + +static constexpr int MAX_CHANNELS = 8; + + +static cassette_image::error flacfile_identify(cassette_image *cassette, cassette_image::Options *opts) +{ + cassette->get_raw_cassette_image()->seek(0, SEEK_SET); + flac_decoder decoder(*cassette->get_raw_cassette_image()); + if (!decoder.reset()) + return cassette_image::error::INVALID_IMAGE; + const int channels = decoder.channels(); + const int sample_rate = decoder.sample_rate(); + const int bits_per_sample = decoder.bits_per_sample(); + const int total_samples = decoder.total_samples(); + decoder.finish(); + + opts->channels = channels; + opts->sample_frequency = sample_rate; + opts->bits_per_sample = bits_per_sample; + + if (channels > MAX_CHANNELS) + return cassette_image::error::INVALID_IMAGE; + else if (channels > 0 && sample_rate > 0 && total_samples > 0) + return cassette_image::error::SUCCESS; + else + return cassette_image::error::INVALID_IMAGE; +} + + +static cassette_image::error flacfile_load(cassette_image *cassette) +{ + cassette->get_raw_cassette_image()->seek(0, SEEK_SET); + flac_decoder decoder(*cassette->get_raw_cassette_image()); + if (!decoder.reset()) + return cassette_image::error::INVALID_IMAGE; + const int channels = decoder.channels(); + const int total_samples = decoder.total_samples(); + + std::unique_ptr samples[MAX_CHANNELS]; + int16_t *channel_samples[MAX_CHANNELS]; + for (int channel = 0; channel < channels; channel++) + { + samples[channel].reset(new (std::nothrow) int16_t [total_samples]); + if (!samples[channel]) + return cassette_image::error::OUT_OF_MEMORY; + channel_samples[channel] = samples[channel].get(); + } + if (!decoder.decode(channel_samples, decoder.total_samples(), false)) + return cassette_image::error::INVALID_IMAGE; + for (int channel = 0; channel < channels; channel++) + { + const cassette_image::error err = cassette->put_samples( + channel, 0.0, (double)total_samples/decoder.sample_rate(), total_samples, + 2, channel_samples[channel], cassette_image::WAVEFORM_16BIT); + if (err != cassette_image::error::SUCCESS) + return err; + } + + return cassette_image::error::SUCCESS; +} + + +const cassette_image::Format cassette_image::flacfile_format = +{ + "flac", + flacfile_identify, + flacfile_load, + nullptr +}; diff --git a/src/lib/formats/flacfile.h b/src/lib/formats/flacfile.h new file mode 100644 index 00000000000..8af8c3263b4 --- /dev/null +++ b/src/lib/formats/flacfile.h @@ -0,0 +1,10 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +#ifndef MAME_FORMATS_FLACFILE_H +#define MAME_FORMATS_FLACFILE_H + +#pragma once + +#include "cassimg.h" + +#endif // MAME_FORMATS_FLACFILE_H diff --git a/src/lib/util/flac.cpp b/src/lib/util/flac.cpp index 3492ec0e095..e80b56b5bda 100644 --- a/src/lib/util/flac.cpp +++ b/src/lib/util/flac.cpp @@ -316,6 +316,9 @@ flac_decoder::flac_decoder() flac_decoder::flac_decoder(const void *buffer, uint32_t length, const void *buffer2, uint32_t length2) : m_decoder(FLAC__stream_decoder_new()), m_file(nullptr), + m_sample_rate(0), + m_channels(0), + m_bits_per_sample(0), m_compressed_offset(0), m_compressed_start(reinterpret_cast(buffer)), m_compressed_length(length), @@ -333,6 +336,9 @@ flac_decoder::flac_decoder(const void *buffer, uint32_t length, const void *buff flac_decoder::flac_decoder(util::read_stream &file) : m_decoder(FLAC__stream_decoder_new()), m_file(&file), + m_sample_rate(0), + m_channels(0), + m_bits_per_sample(0), m_compressed_offset(0), m_compressed_start(nullptr), m_compressed_length(0),