1 /*
2  * SampleFormatFLAC.cpp
3  * --------------------
4  * Purpose: FLAC sample import.
5  * Notes  :
6  * Authors: OpenMPT Devs
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 
11 #include "stdafx.h"
12 #include "Sndfile.h"
13 #ifdef MODPLUG_TRACKER
14 #include "../mptrack/TrackerSettings.h"
15 #endif //MODPLUG_TRACKER
16 #ifndef MODPLUG_NO_FILESAVE
17 #include "../common/mptFileIO.h"
18 #endif
19 #include "../common/misc_util.h"
20 #include "Tagging.h"
21 #include "Loaders.h"
22 #include "WAVTools.h"
23 #include "../common/FileReader.h"
24 #include "modsmp_ctrl.h"
25 #include "openmpt/soundbase/Copy.hpp"
26 #include "openmpt/soundbase/SampleConvert.hpp"
27 #include "openmpt/soundbase/SampleDecode.hpp"
28 #include "../soundlib/SampleCopy.h"
29 #include "../soundlib/ModSampleCopy.h"
30 #include "mpt/io/base.hpp"
31 #include "mpt/io/io.hpp"
32 #include "mpt/io/io_stdstream.hpp"
33 //#include "mpt/crc/crc.hpp"
34 #include "OggStream.h"
35 #ifdef MPT_WITH_OGG
36 #if MPT_COMPILER_CLANG
37 #pragma clang diagnostic push
38 #pragma clang diagnostic ignored "-Wreserved-id-macro"
39 #endif // MPT_COMPILER_CLANG
40 #include <ogg/ogg.h>
41 #if MPT_COMPILER_CLANG
42 #pragma clang diagnostic pop
43 #endif // MPT_COMPILER_CLANG
44 #endif // MPT_WITH_OGG
45 #ifdef MPT_WITH_FLAC
46 #if MPT_COMPILER_CLANG
47 #pragma clang diagnostic push
48 #pragma clang diagnostic ignored "-Wreserved-id-macro"
49 #endif // MPT_COMPILER_CLANG
50 #include <FLAC/stream_decoder.h>
51 #include <FLAC/stream_encoder.h>
52 #include <FLAC/metadata.h>
53 #if MPT_COMPILER_CLANG
54 #pragma clang diagnostic pop
55 #endif // MPT_COMPILER_CLANG
56 #endif // MPT_WITH_FLAC
57 
58 
59 OPENMPT_NAMESPACE_BEGIN
60 
61 
62 ///////////////////////////////////////////////////////////////////////////////////////////////////
63 // FLAC Samples
64 
65 #ifdef MPT_WITH_FLAC
66 
67 struct FLACDecoder
68 {
69 	FileReader &file;
70 	CSoundFile &sndFile;
71 	SAMPLEINDEX sample;
72 	bool ready;
73 
FLACDecoderFLACDecoder74 	FLACDecoder(FileReader &f, CSoundFile &sf, SAMPLEINDEX smp) : file(f), sndFile(sf), sample(smp), ready(false) { }
75 
read_cbFLACDecoder76 	static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *client_data)
77 	{
78 		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
79 		if(*bytes > 0)
80 		{
81 			FileReader::off_t readBytes = *bytes;
82 			LimitMax(readBytes, file.BytesLeft());
83 			file.ReadRaw(mpt::byte_cast<mpt::byte_span>(mpt::span(buffer, readBytes)));
84 			*bytes = readBytes;
85 			if(*bytes == 0)
86 				return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
87 			else
88 				return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
89 		} else
90 		{
91 			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
92 		}
93 	}
94 
seek_cbFLACDecoder95 	static FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *, FLAC__uint64 absolute_byte_offset, void *client_data)
96 	{
97 		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
98 		if(!file.Seek(static_cast<FileReader::off_t>(absolute_byte_offset)))
99 			return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
100 		else
101 			return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
102 	}
103 
tell_cbFLACDecoder104 	static FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *, FLAC__uint64 *absolute_byte_offset, void *client_data)
105 	{
106 		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
107 		*absolute_byte_offset = file.GetPosition();
108 		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
109 	}
110 
length_cbFLACDecoder111 	static FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *, FLAC__uint64 *stream_length, void *client_data)
112 	{
113 		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
114 		*stream_length = file.GetLength();
115 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
116 	}
117 
eof_cbFLACDecoder118 	static FLAC__bool eof_cb(const FLAC__StreamDecoder *, void *client_data)
119 	{
120 		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
121 		return file.NoBytesLeft();
122 	}
123 
write_cbFLACDecoder124 	static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
125 	{
126 		FLACDecoder &client = *static_cast<FLACDecoder *>(client_data);
127 		ModSample &sample = client.sndFile.GetSample(client.sample);
128 
129 		if(frame->header.number.sample_number >= sample.nLength || !client.ready)
130 		{
131 			// We're reading beyond the sample size already, or we aren't even ready to decode yet!
132 			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
133 		}
134 
135 		// Number of samples to be copied in this call
136 		const SmpLength copySamples = std::min(static_cast<SmpLength>(frame->header.blocksize), static_cast<SmpLength>(sample.nLength - frame->header.number.sample_number));
137 		// Number of target channels
138 		const uint8 modChannels = sample.GetNumChannels();
139 		// Offset (in samples) into target data
140 		const size_t offset = static_cast<size_t>(frame->header.number.sample_number) * modChannels;
141 		// Source size in bytes
142 		const size_t srcSize = frame->header.blocksize * 4;
143 		// Source bit depth
144 		const unsigned int bps = frame->header.bits_per_sample;
145 
146 		MPT_ASSERT((bps <= 8 && sample.GetElementarySampleSize() == 1) || (bps > 8 && sample.GetElementarySampleSize() == 2));
147 		MPT_ASSERT(modChannels <= FLAC__stream_decoder_get_channels(decoder));
148 		MPT_ASSERT(bps == FLAC__stream_decoder_get_bits_per_sample(decoder));
149 		MPT_UNREFERENCED_PARAMETER(decoder); // decoder is unused if ASSERTs are compiled out
150 
151 		// Do the sample conversion
152 		for(uint8 chn = 0; chn < modChannels; chn++)
153 		{
154 			if(bps <= 8)
155 			{
156 				int8 *sampleData8 = sample.sample8() + offset;
157 				CopySample<SC::ConversionChain<SC::ConvertShift< int8, int32,  0>, SC::DecodeIdentity<int32> > >(sampleData8  + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
158 			} else if(bps <= 16)
159 			{
160 				int16 *sampleData16 = sample.sample16() + offset;
161 				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32,  0>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
162 			} else if(bps <= 24)
163 			{
164 				int16 *sampleData16 = sample.sample16() + offset;
165 				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32,  8>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
166 			} else if(bps <= 32)
167 			{
168 				int16 *sampleData16 = sample.sample16() + offset;
169 				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32, 16>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
170 			}
171 		}
172 
173 		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
174 	}
175 
metadata_cbFLACDecoder176 	static void metadata_cb(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data)
177 	{
178 		FLACDecoder &client = *static_cast<FLACDecoder *>(client_data);
179 		if(client.sample > client.sndFile.GetNumSamples())
180 		{
181 			client.sndFile.m_nSamples = client.sample;
182 		}
183 		ModSample &sample = client.sndFile.GetSample(client.sample);
184 
185 		if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0)
186 		{
187 			// Init sample information
188 			client.sndFile.DestroySampleThreadsafe(client.sample);
189 			client.sndFile.m_szNames[client.sample] = "";
190 			sample.Initialize();
191 			sample.uFlags.set(CHN_16BIT, metadata->data.stream_info.bits_per_sample > 8);
192 			sample.uFlags.set(CHN_STEREO, metadata->data.stream_info.channels > 1);
193 			sample.nLength = mpt::saturate_cast<SmpLength>(metadata->data.stream_info.total_samples);
194 			LimitMax(sample.nLength, MAX_SAMPLE_LENGTH);
195 			sample.nC5Speed = metadata->data.stream_info.sample_rate;
196 			client.ready = (sample.AllocateSample() != 0);
197 		} else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4) && client.ready)
198 		{
199 			// Try reading RIFF loop points and other sample information
200 			FileReader data(mpt::as_span(metadata->data.application.data, metadata->length));
201 			FileReader::ChunkList<RIFFChunk> chunks = data.ReadChunks<RIFFChunk>(2);
202 
203 			// We're not really going to read a WAV file here because there will be only one RIFF chunk per metadata event, but we can still re-use the code for parsing RIFF metadata...
204 			WAVReader riffReader(data);
205 			riffReader.FindMetadataChunks(chunks);
206 			riffReader.ApplySampleSettings(sample, client.sndFile.GetCharsetInternal(), client.sndFile.m_szNames[client.sample]);
207 		} else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && client.ready)
208 		{
209 			// Try reading Vorbis Comments for sample title, sample rate and loop points
210 			SmpLength loopStart = 0, loopLength = 0;
211 			for(FLAC__uint32 i = 0; i < metadata->data.vorbis_comment.num_comments; i++)
212 			{
213 				const char *tag = mpt::byte_cast<const char *>(metadata->data.vorbis_comment.comments[i].entry);
214 				const FLAC__uint32 length = metadata->data.vorbis_comment.comments[i].length;
215 				if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6))
216 				{
217 					client.sndFile.m_szNames[client.sample] = mpt::ToCharset(client.sndFile.GetCharsetInternal(), mpt::Charset::UTF8, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, tag + 6, length - 6));
218 				} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11))
219 				{
220 					uint32 sampleRate = ConvertStrTo<uint32>(tag + 11);
221 					if(sampleRate > 0) sample.nC5Speed = sampleRate;
222 				} else if(length > 10 && !mpt::CompareNoCaseAscii(tag, "LOOPSTART=", 10))
223 				{
224 					loopStart = ConvertStrTo<SmpLength>(tag + 10);
225 				} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "LOOPLENGTH=", 11))
226 				{
227 					loopLength = ConvertStrTo<SmpLength>(tag + 11);
228 				}
229 			}
230 			if(loopLength > 0)
231 			{
232 				sample.nLoopStart = loopStart;
233 				sample.nLoopEnd = loopStart + loopLength;
234 				sample.uFlags.set(CHN_LOOP);
235 				sample.SanitizeLoops();
236 			}
237 		}
238 	}
239 
error_cbFLACDecoder240 	static void error_cb(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *)
241 	{
242 	}
243 };
244 
245 #endif // MPT_WITH_FLAC
246 
247 
ReadFLACSample(SAMPLEINDEX sample,FileReader & file)248 bool CSoundFile::ReadFLACSample(SAMPLEINDEX sample, FileReader &file)
249 {
250 #ifdef MPT_WITH_FLAC
251 	file.Rewind();
252 	bool isOgg = false;
253 #ifdef MPT_WITH_OGG
254 	uint32 oggFlacBitstreamSerial = 0;
255 #endif
256 	// Check whether we are dealing with native FLAC, OggFlac or no FLAC at all.
257 	if(file.ReadMagic("fLaC"))
258 	{ // ok
259 		isOgg = false;
260 #ifdef MPT_WITH_OGG
261 	} else if(file.ReadMagic("OggS"))
262 	{ // use libogg to find the first OggFlac stream header
263 		file.Rewind();
264 		bool oggOK = false;
265 		bool needMoreData = true;
266 		constexpr long bufsize = 65536;
267 		std::size_t readSize = 0;
268 		char *buf = nullptr;
269 		ogg_sync_state oy;
270 		MemsetZero(oy);
271 		ogg_page og;
272 		MemsetZero(og);
273 		std::map<uint32, ogg_stream_state*> oggStreams;
274 		ogg_packet op;
275 		MemsetZero(op);
276 		if(ogg_sync_init(&oy) != 0)
277 		{
278 			return false;
279 		}
280 		while(needMoreData)
281 		{
282 			if(file.NoBytesLeft())
283 			{ // stop at EOF
284 				oggOK = false;
285 				needMoreData = false;
286 				break;
287 			}
288 			buf = ogg_sync_buffer(&oy, bufsize);
289 			if(!buf)
290 			{
291 				oggOK = false;
292 				needMoreData = false;
293 				break;
294 			}
295 			readSize = file.ReadRaw(mpt::span(buf, bufsize)).size();
296 			if(ogg_sync_wrote(&oy, static_cast<long>(readSize)) != 0)
297 			{
298 				oggOK = false;
299 				needMoreData = false;
300 				break;
301 			}
302 			while(ogg_sync_pageout(&oy, &og) == 1)
303 			{
304 				if(!ogg_page_bos(&og))
305 				{ // we stop scanning when seeing the first noo-begin-of-stream page
306 					oggOK = false;
307 					needMoreData = false;
308 					break;
309 				}
310 				uint32 serial = ogg_page_serialno(&og);
311 				if(!oggStreams[serial])
312 				{ // previously unseen stream serial
313 					oggStreams[serial] = new ogg_stream_state();
314 					MemsetZero(*(oggStreams[serial]));
315 					if(ogg_stream_init(oggStreams[serial], serial) != 0)
316 					{
317 						delete oggStreams[serial];
318 						oggStreams.erase(serial);
319 						oggOK = false;
320 						needMoreData = false;
321 						break;
322 					}
323 				}
324 				if(ogg_stream_pagein(oggStreams[serial], &og) != 0)
325 				{ // invalid page
326 					oggOK = false;
327 					needMoreData = false;
328 					break;
329 				}
330 				if(ogg_stream_packetout(oggStreams[serial], &op) != 1)
331 				{ // partial or broken packet, continue with more data
332 					continue;
333 				}
334 				if(op.packetno != 0)
335 				{ // non-begin-of-stream packet.
336 					// This should not appear on first page for any known ogg codec,
337 					// but deal gracefully with badly mused streams in that regard.
338 					continue;
339 				}
340 				FileReader packet(mpt::as_span(op.packet, op.bytes));
341 				if(packet.ReadIntLE<uint8>() == 0x7f && packet.ReadMagic("FLAC"))
342 				{ // looks like OggFlac
343 					oggOK = true;
344 					oggFlacBitstreamSerial = serial;
345 					needMoreData = false;
346 					break;
347 				}
348 			}
349 		}
350 		while(oggStreams.size() > 0)
351 		{
352 			uint32 serial = oggStreams.begin()->first;
353 			ogg_stream_clear(oggStreams[serial]);
354 			delete oggStreams[serial];
355 			oggStreams.erase(serial);
356 		}
357 		ogg_sync_clear(&oy);
358 		if(!oggOK)
359 		{
360 			return false;
361 		}
362 		isOgg = true;
363 #else // !MPT_WITH_OGG
364 	} else if(file.CanRead(78) && file.ReadMagic("OggS"))
365 	{ // first OggFlac page is exactly 78 bytes long
366 		// only support plain OggFlac here with the FLAC logical bitstream being the first one
367 		uint8 oggPageVersion = file.ReadIntLE<uint8>();
368 		uint8 oggPageHeaderType = file.ReadIntLE<uint8>();
369 		uint64 oggPageGranulePosition = file.ReadIntLE<uint64>();
370 		uint32 oggPageBitstreamSerialNumber = file.ReadIntLE<uint32>();
371 		uint32 oggPageSequenceNumber = file.ReadIntLE<uint32>();
372 		uint32 oggPageChecksum = file.ReadIntLE<uint32>();
373 		uint8 oggPageSegments = file.ReadIntLE<uint8>();
374 		uint8 oggPageSegmentLength = file.ReadIntLE<uint8>();
375 		if(oggPageVersion != 0)
376 		{ // unknown Ogg version
377 			return false;
378 		}
379 		if(!(oggPageHeaderType & 0x02) || (oggPageHeaderType& 0x01))
380 		{ // not BOS or continuation
381 			return false;
382 		}
383 		if(oggPageGranulePosition != 0)
384 		{ // not starting position
385 			return false;
386 		}
387 		if(oggPageSequenceNumber != 0)
388 		{ // not first page
389 			return false;
390 		}
391 		// skip CRC check for now
392 		if(oggPageSegments != 1)
393 		{ // first OggFlac page must contain exactly 1 segment
394 			return false;
395 		}
396 		if(oggPageSegmentLength != 51)
397 		{ // segment length must be 51 bytes in OggFlac mapping
398 			return false;
399 		}
400 		if(file.ReadIntLE<uint8>() != 0x7f)
401 		{ // OggFlac mapping demands 0x7f packet type
402 			return false;
403 		}
404 		if(!file.ReadMagic("FLAC"))
405 		{ // OggFlac magic
406 			return false;
407 		}
408 		if(file.ReadIntLE<uint8>() != 0x01)
409 		{ // OggFlac major version
410 			return false;
411 		}
412 		// by now, we are pretty confident that we are not parsing random junk
413 		isOgg = true;
414 #endif // MPT_WITH_OGG
415 	} else
416 	{
417 		return false;
418 	}
419 	file.Rewind();
420 
421 	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
422 	if(decoder == nullptr)
423 	{
424 		return false;
425 	}
426 
427 #ifdef MPT_WITH_OGG
428 	if(isOgg)
429 	{
430 		// force flac decoding of the logical bitstream that actually is OggFlac
431 		if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, oggFlacBitstreamSerial))
432 		{
433 			FLAC__stream_decoder_delete(decoder);
434 			return false;
435 		}
436 	}
437 #endif
438 
439 	// Give me all the metadata!
440 	FLAC__stream_decoder_set_metadata_respond_all(decoder);
441 
442 	FLACDecoder client(file, *this, sample);
443 
444 	// Init decoder
445 	FLAC__StreamDecoderInitStatus initStatus = isOgg ?
446 		FLAC__stream_decoder_init_ogg_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client)
447 		:
448 		FLAC__stream_decoder_init_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client)
449 		;
450 	if(initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK)
451 	{
452 		FLAC__stream_decoder_delete(decoder);
453 		return false;
454 	}
455 
456 	// Decode file
457 	FLAC__stream_decoder_process_until_end_of_stream(decoder);
458 	FLAC__stream_decoder_finish(decoder);
459 	FLAC__stream_decoder_delete(decoder);
460 
461 	if(client.ready && Samples[sample].HasSampleData())
462 	{
463 		Samples[sample].Convert(MOD_TYPE_IT, GetType());
464 		Samples[sample].PrecomputeLoops(*this, false);
465 		return true;
466 	}
467 #else
468 	MPT_UNREFERENCED_PARAMETER(sample);
469 	MPT_UNREFERENCED_PARAMETER(file);
470 #endif // MPT_WITH_FLAC
471 	return false;
472 }
473 
474 
475 #ifdef MPT_WITH_FLAC
476 
477 // RAII-style helper struct for FLAC encoder
478 struct FLAC__StreamEncoder_RAII
479 {
480 	std::ostream &f;
481 	FLAC__StreamEncoder *encoder = nullptr;
482 
operator FLAC__StreamEncoder*FLAC__StreamEncoder_RAII483 	operator FLAC__StreamEncoder *() { return encoder; }
484 
FLAC__StreamEncoder_RAIIFLAC__StreamEncoder_RAII485 	FLAC__StreamEncoder_RAII(std::ostream &f_) : f(f_), encoder(FLAC__stream_encoder_new()) { }
~FLAC__StreamEncoder_RAIIFLAC__StreamEncoder_RAII486 	~FLAC__StreamEncoder_RAII()
487 	{
488 		FLAC__stream_encoder_delete(encoder);
489 	}
490 
StreamEncoderWriteCallbackFLAC__StreamEncoder_RAII491 	static FLAC__StreamEncoderWriteStatus StreamEncoderWriteCallback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
492 	{
493 		mpt::ofstream & file = *reinterpret_cast<mpt::ofstream*>(client_data);
494 		MPT_UNUSED_VARIABLE(encoder);
495 		MPT_UNUSED_VARIABLE(samples);
496 		MPT_UNUSED_VARIABLE(current_frame);
497 		if(!mpt::IO::WriteRaw(file, mpt::as_span(buffer, bytes)))
498 		{
499 			return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
500 		}
501 		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
502 	}
StreamEncoderSeekCallbackFLAC__StreamEncoder_RAII503 	static FLAC__StreamEncoderSeekStatus StreamEncoderSeekCallback(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
504 	{
505 		mpt::ofstream & file = *reinterpret_cast<mpt::ofstream*>(client_data);
506 		MPT_UNUSED_VARIABLE(encoder);
507 		if(!mpt::in_range<mpt::IO::Offset>(absolute_byte_offset))
508 		{
509 			return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
510 		}
511 		if(!mpt::IO::SeekAbsolute(file, static_cast<mpt::IO::Offset>(absolute_byte_offset)))
512 		{
513 			return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
514 		}
515 		return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
516 	}
StreamEncoderTellCallbackFLAC__StreamEncoder_RAII517 	static FLAC__StreamEncoderTellStatus StreamEncoderTellCallback(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
518 	{
519 		mpt::ofstream & file = *reinterpret_cast<mpt::ofstream*>(client_data);
520 		MPT_UNUSED_VARIABLE(encoder);
521 		mpt::IO::Offset pos = mpt::IO::TellWrite(file);
522 		if(pos < 0)
523 		{
524 			return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
525 		}
526 		if(!mpt::in_range<FLAC__uint64>(pos))
527 		{
528 			return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
529 		}
530 		*absolute_byte_offset = static_cast<FLAC__uint64>(pos);
531 		return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
532 	}
533 
534 };
535 
536 class FLAC__StreamMetadata_RAII : public std::vector<FLAC__StreamMetadata *>
537 {
538 public:
FLAC__StreamMetadata_RAII(std::initializer_list<FLAC__StreamMetadata * > init)539 	FLAC__StreamMetadata_RAII(std::initializer_list<FLAC__StreamMetadata *> init)
540 		: std::vector<FLAC__StreamMetadata *>(init)
541 	{ }
542 
~FLAC__StreamMetadata_RAII()543 	~FLAC__StreamMetadata_RAII()
544 	{
545 		for(auto m : *this)
546 		{
547 			FLAC__metadata_object_delete(m);
548 		}
549 	}
550 };
551 
552 #endif
553 
554 
555 #ifndef MODPLUG_NO_FILESAVE
SaveFLACSample(SAMPLEINDEX nSample,std::ostream & f) const556 bool CSoundFile::SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const
557 {
558 #ifdef MPT_WITH_FLAC
559 	const ModSample &sample = Samples[nSample];
560 	if(sample.uFlags[CHN_ADLIB])
561 		return false;
562 
563 	FLAC__StreamEncoder_RAII encoder(f);
564 	if(encoder == nullptr)
565 		return false;
566 
567 	uint32 sampleRate = sample.GetSampleRate(GetType());
568 
569 	// First off, set up all the metadata...
570 	FLAC__StreamMetadata_RAII metadata =
571 	{
572 		FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT),
573 		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// MPT sample information
574 		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// Loop points
575 		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// Cue points
576 	};
577 
578 	unsigned numBlocks = 2;
579 	if(metadata[0])
580 	{
581 		// Store sample name
582 		FLAC__StreamMetadata_VorbisComment_Entry entry;
583 		FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", mpt::ToCharset(mpt::Charset::UTF8, GetCharsetInternal(), m_szNames[nSample]).c_str());
584 		FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
585 		FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ENCODER", mpt::ToCharset(mpt::Charset::UTF8, Version::Current().GetOpenMPTVersionString()).c_str());
586 		FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
587 		if(sampleRate > FLAC__MAX_SAMPLE_RATE)
588 		{
589 			// FLAC only supports a sample rate of up to 655350 Hz.
590 			// Store the real sample rate in a custom Vorbis comment.
591 			FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "SAMPLERATE", mpt::afmt::val(sampleRate).c_str());
592 			FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
593 		}
594 	}
595 	if(metadata[1])
596 	{
597 		// Write MPT sample information
598 		memcpy(metadata[1]->data.application.id, "riff", 4);
599 
600 		struct
601 		{
602 			RIFFChunk header;
603 			WAVExtraChunk mptInfo;
604 		} chunk;
605 
606 		chunk.header.id = RIFFChunk::idxtra;
607 		chunk.header.length = sizeof(WAVExtraChunk);
608 
609 		chunk.mptInfo.ConvertToWAV(sample, GetType());
610 
611 		const uint32 length = sizeof(RIFFChunk) + sizeof(WAVExtraChunk);
612 
613 		FLAC__metadata_object_application_set_data(metadata[1], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
614 	}
615 	if(metadata[numBlocks] && (sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP] || ModCommand::IsNote(sample.rootNote)))
616 	{
617 		// Store loop points / root note information
618 		memcpy(metadata[numBlocks]->data.application.id, "riff", 4);
619 
620 		struct
621 		{
622 			RIFFChunk header;
623 			WAVSampleInfoChunk info;
624 			WAVSampleLoop loops[2];
625 		} chunk;
626 
627 		chunk.header.id = RIFFChunk::idsmpl;
628 		chunk.header.length = sizeof(WAVSampleInfoChunk);
629 
630 		chunk.info.ConvertToWAV(sample.GetSampleRate(GetType()), sample.rootNote);
631 
632 		if(sample.uFlags[CHN_SUSTAINLOOP])
633 		{
634 			chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nSustainStart, sample.nSustainEnd, sample.uFlags[CHN_PINGPONGSUSTAIN]);
635 			chunk.header.length += sizeof(WAVSampleLoop);
636 		}
637 		if(sample.uFlags[CHN_LOOP])
638 		{
639 			chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nLoopStart, sample.nLoopEnd, sample.uFlags[CHN_PINGPONGLOOP]);
640 			chunk.header.length += sizeof(WAVSampleLoop);
641 		}
642 
643 		const uint32 length = sizeof(RIFFChunk) + chunk.header.length;
644 
645 		FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
646 		numBlocks++;
647 	}
648 	if(metadata[numBlocks] && sample.HasCustomCuePoints())
649 	{
650 		// Store cue points
651 		memcpy(metadata[numBlocks]->data.application.id, "riff", 4);
652 
653 		struct
654 		{
655 			RIFFChunk header;
656 			uint32le numPoints;
657 			WAVCuePoint cues[mpt::array_size<decltype(sample.cues)>::size];
658 		} chunk{};
659 
660 		chunk.header.id = RIFFChunk::idcue_;
661 		chunk.header.length = 4 + sizeof(chunk.cues);
662 		chunk.numPoints = mpt::saturate_cast<uint32>(std::size(sample.cues));
663 
664 		for(uint32 i = 0; i < std::size(sample.cues); i++)
665 		{
666 			chunk.cues[i].ConvertToWAV(i, sample.cues[i]);
667 		}
668 
669 		const uint32 length = sizeof(RIFFChunk) + chunk.header.length;
670 
671 		FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
672 		numBlocks++;
673 	}
674 
675 	// FLAC allows a maximum sample rate of 655350 Hz.
676 	// If the real rate is higher, we store it in a Vorbis comment above.
677 	LimitMax(sampleRate, FLAC__MAX_SAMPLE_RATE);
678 	if(!FLAC__format_sample_rate_is_subset(sampleRate))
679 	{
680 		// FLAC only supports 10 Hz granularity for frequencies above 65535 Hz if the streamable subset is chosen.
681 		FLAC__stream_encoder_set_streamable_subset(encoder, false);
682 	}
683 	FLAC__stream_encoder_set_channels(encoder, sample.GetNumChannels());
684 	FLAC__stream_encoder_set_bits_per_sample(encoder, sample.GetElementarySampleSize() * 8);
685 	FLAC__stream_encoder_set_sample_rate(encoder, sampleRate);
686 	FLAC__stream_encoder_set_total_samples_estimate(encoder, sample.nLength);
687 	FLAC__stream_encoder_set_metadata(encoder, metadata.data(), numBlocks);
688 #ifdef MODPLUG_TRACKER
689 	FLAC__stream_encoder_set_compression_level(encoder, TrackerSettings::Instance().m_FLACCompressionLevel);
690 #endif // MODPLUG_TRACKER
691 
692 	bool success = FLAC__stream_encoder_init_stream(encoder, &FLAC__StreamEncoder_RAII::StreamEncoderWriteCallback, &FLAC__StreamEncoder_RAII::StreamEncoderSeekCallback, &FLAC__StreamEncoder_RAII::StreamEncoderTellCallback, nullptr, &encoder.f) == FLAC__STREAM_ENCODER_INIT_STATUS_OK;
693 
694 	// Convert and encode sample data
695 	SmpLength framesRemain = sample.nLength, framesRead = 0;
696 	const uint8 numChannels = sample.GetNumChannels();
697 	FLAC__int32 buffer[mpt::IO::BUFFERSIZE_TINY];
698 	while(framesRemain && success)
699 	{
700 		const SmpLength copyFrames = std::min(framesRemain, mpt::saturate_cast<SmpLength>(std::size(buffer) / numChannels));
701 
702 		// First, convert to a 32-bit integer buffer
703 		switch(sample.GetElementarySampleSize())
704 		{
705 		case 1: std::copy(sample.sample8() + framesRead * numChannels, sample.sample8() + (framesRead + copyFrames) * numChannels, std::begin(buffer)); break;
706 		case 2: std::copy(sample.sample16() + framesRead * numChannels, sample.sample16() + (framesRead + copyFrames) * numChannels, std::begin(buffer)); break;
707 		default: MPT_ASSERT_NOTREACHED();
708 		}
709 
710 		// Now do the actual encoding
711 		success = FLAC__stream_encoder_process_interleaved(encoder, buffer, copyFrames) != static_cast<FLAC__bool>(false);
712 
713 		framesRead += copyFrames;
714 		framesRemain -= copyFrames;
715 	}
716 
717 	FLAC__stream_encoder_finish(encoder);
718 
719 	return success;
720 #else
721 	MPT_UNREFERENCED_PARAMETER(nSample);
722 	MPT_UNREFERENCED_PARAMETER(f);
723 	return false;
724 #endif // MPT_WITH_FLAC
725 }
726 #endif // MODPLUG_NO_FILESAVE
727 
728 
729 OPENMPT_NAMESPACE_END
730