aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Encoder/enc_flac/AudioCoderFlac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Encoder/enc_flac/AudioCoderFlac.cpp')
-rw-r--r--Src/Plugins/Encoder/enc_flac/AudioCoderFlac.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/Src/Plugins/Encoder/enc_flac/AudioCoderFlac.cpp b/Src/Plugins/Encoder/enc_flac/AudioCoderFlac.cpp
new file mode 100644
index 00000000..38bb124e
--- /dev/null
+++ b/Src/Plugins/Encoder/enc_flac/AudioCoderFlac.cpp
@@ -0,0 +1,203 @@
+#include "AudioCoderFlac.h"
+#include <bfc/platform/types.h>
+#include <FLAC/metadata.h>
+
+AudioCoderFlac::AudioCoderFlac(unsigned int nch, unsigned int bps, unsigned int samplerate, unsigned int compression)
+{
+ /* initialize stuff first so we can clean up safely if things go wrong */
+ finished = false;
+ finishedBytes = 0;
+ padding = 0;
+ encoder = 0;
+ win32State.bytesWritten = 0;
+ win32State.handle = INVALID_HANDLE_VALUE;
+ tempFile[0]=0;
+
+ wchar_t tempPath[MAX_PATH-14] = {0};
+ GetTempPath(MAX_PATH-14, tempPath);
+ GetTempFileName(tempPath, L"wfl", 0, tempFile);
+ win32State.handle = CreateFile(tempFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
+
+ if (win32State.handle != INVALID_HANDLE_VALUE)
+ {
+ this->nch = nch;
+ this->bps = bps;
+ encoder = FLAC__stream_encoder_new();
+
+ if (!encoder)
+ return;
+
+ // set stream info
+ if (!FLAC__stream_encoder_set_channels(encoder, nch)
+ || !FLAC__stream_encoder_set_bits_per_sample(encoder, bps)
+ || !FLAC__stream_encoder_set_sample_rate(encoder, samplerate)
+ || !FLAC__stream_encoder_set_total_samples_estimate(encoder, 0)
+ || !FLAC__stream_encoder_set_compression_level(encoder, compression)
+ || !FLAC__stream_encoder_set_blocksize(encoder, 0))
+ {
+ FLAC__stream_encoder_delete(encoder);
+ encoder=0;
+ return;
+ }
+ // TODO: set any more config stuff
+
+ // TODO: seektable?
+ //FLAC__StreamMetadata *seektable = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+
+ padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+ if (padding)
+ {
+ padding->length = 16384; // TODO: configurable padding size
+ if (!FLAC__stream_encoder_set_metadata(encoder, &padding, 1))
+ {
+ FLAC__stream_encoder_delete(encoder);
+ encoder=0;
+ return;
+ }
+ }
+
+ if (FLAC__stream_encoder_init_stream(encoder, Win32_Write, Win32_Seek, Win32_Tell, NULL, &win32State) != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+ {
+ FLAC__stream_encoder_delete(encoder);
+ encoder=0;
+ return;
+ }
+ }
+}
+
+bool AudioCoderFlac::OK()
+{
+ if (!encoder)
+ return false;
+
+ return FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK;
+}
+
+AudioCoderFlac::~AudioCoderFlac()
+{
+ if (encoder)
+ FLAC__stream_encoder_delete(encoder);
+
+ if (padding)
+ FLAC__metadata_object_delete(padding);
+
+ if (win32State.handle != INVALID_HANDLE_VALUE)
+ CloseHandle(win32State.handle);
+
+}
+
+static void Copy8(FLAC__int32 *buffer, void *inputData, int numSamples)
+{
+ uint8_t *in = (uint8_t *)inputData;
+
+ for (int i=0;i<numSamples;i++)
+ {
+ buffer[i] = (FLAC__int32)in[i];
+ }
+}
+
+static void Copy16(FLAC__int32 *buffer, void *inputData, int numSamples)
+{
+ int16_t *in = (int16_t *)inputData;
+
+ for (int i=0;i<numSamples;i++)
+ {
+ buffer[i] = (FLAC__int32)in[i];
+ }
+}
+
+static void Copy24(FLAC__int32 *buffer, void *inputData, int numSamples)
+{
+ uint8_t *in = (uint8_t *)inputData;
+
+ for (int i=0;i<numSamples;i++)
+ {
+ FLAC__int32 val = (((FLAC__int32)in[0]) << 0);
+ val = val | (((FLAC__int32)in[1]) << 8);
+ val = val | (((FLAC__int32)in[2]) << 16);
+
+ buffer[i] = (FLAC__int32)val;
+ in+=3;
+ }
+}
+
+static void Copy32(FLAC__int32 *buffer, void *inputData, int numSamples)
+{
+ int32_t *in = (int32_t *)inputData;
+
+ for (int i=0;i<numSamples;i++)
+ {
+ buffer[i] = (FLAC__int32)in[i];
+ }
+}
+
+int AudioCoderFlac::Encode(int framepos, void *in, int in_avail, int *in_used, void *out, int out_avail)
+{
+ FLAC__int32 buffer[65536];
+
+
+ FLAC__uint64 startBytes = win32State.bytesWritten;
+
+ if (!in_avail)
+ {
+ if (finished)
+ {
+ int ret = (int)finishedBytes;
+ finishedBytes = 0;
+ return ret;
+ }
+ return 0;
+ }
+
+
+ int numSamples = in_avail/(bps/8);
+
+ if (numSamples>65536)
+ numSamples = 65536;
+
+ switch (bps)
+ {
+ case 8:
+ Copy8(buffer, in, numSamples);
+ break;
+ case 16:
+ Copy16(buffer, in, numSamples);
+ break;
+ case 24:
+ Copy24(buffer, in, numSamples);
+ break;
+ case 32:
+ Copy32(buffer, in, numSamples);
+ break;
+ }
+
+ FLAC__bool result = FLAC__stream_encoder_process_interleaved(encoder, buffer, numSamples/nch);
+
+ if (result)
+ {
+ *in_used = numSamples*(bps/8);
+ return (int)(win32State.bytesWritten - startBytes);
+ }
+
+ return 0;
+}
+
+void AudioCoderFlac::PrepareToFinish()
+{
+ FLAC__uint64 startBytes = win32State.bytesWritten;
+ FLAC__stream_encoder_finish(encoder);
+ finishedBytes = win32State.bytesWritten - startBytes;
+}
+
+void AudioCoderFlac::Finish(const wchar_t *destination)
+{
+ if (win32State.handle != INVALID_HANDLE_VALUE)
+ CloseHandle(win32State.handle);
+
+ win32State.handle = INVALID_HANDLE_VALUE;
+ if (!MoveFile(tempFile, destination))
+ {
+ if (CopyFile(tempFile, destination, FALSE))
+ DeleteFile(tempFile);
+ }
+} \ No newline at end of file