summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-07-07 20:26:21 +0200
committerGravatar Alexey Yakovenko <wakeroid@gmail.com>2009-07-07 20:26:21 +0200
commit52667820e1a76d97d0daca25b9621db86e11476d (patch)
treeb36311626b262e7b8ec179d39926e84be52f56f4
parentdf0bf69ac2c5ee6473e9e648dcaa1f4551a9b001 (diff)
flac support
-rw-r--r--Jamfile4
-rw-r--r--cflac.c141
-rw-r--r--cflac.h8
-rw-r--r--playlist.c4
4 files changed, 155 insertions, 2 deletions
diff --git a/Jamfile b/Jamfile
index dee06bab..ac11d837 100644
--- a/Jamfile
+++ b/Jamfile
@@ -16,8 +16,8 @@ HDRS += /usr/include/pango-1.0 ;
HDRS += /usr/include/cairo ;
Main deadbeef :
- codec.c cvorbis.c cmp3.c cgme.c cmod.c cwav.c playlist.c psdl.c main.c support.c interface.c callbacks.c threading.c messagepump.c gtkplaylist.c ;
+ codec.c cvorbis.c cmp3.c cgme.c cmod.c cwav.c cflac.c playlist.c psdl.c main.c support.c interface.c callbacks.c threading.c messagepump.c gtkplaylist.c ;
-LINKLIBS on deadbeef = -lmikmod -lm -lvorbis -logg -lvorbisfile -lmad -lSDL -lsamplerate -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lgthread-2.0 -lstdc++ ;
+LINKLIBS on deadbeef = -lmikmod -lm -lvorbis -logg -lvorbisfile -lmad -lFLAC -lSDL -lsamplerate -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lgthread-2.0 -lstdc++ ;
LinkLibraries deadbeef : libgme ;
diff --git a/cflac.c b/cflac.c
new file mode 100644
index 00000000..3310bcfc
--- /dev/null
+++ b/cflac.c
@@ -0,0 +1,141 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <FLAC/stream_decoder.h>
+#include "codec.h"
+#include "cflac.h"
+#include "common.h"
+
+static FLAC__StreamDecoder *decoder = 0;
+#define BUFFERSIZE 40000
+static char buffer[BUFFERSIZE];
+static int remaining; // bytes remaining in buffer from last read
+
+FLAC__StreamDecoderWriteStatus
+cflac_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const inputbuffer[], void *client_data) {
+ if (frame->header.blocksize == 0) {
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ int readbytes = frame->header.blocksize * cflac.info.channels * cflac.info.bitsPerSample / 8;
+ int bufsize = BUFFERSIZE-remaining;
+ int bufsamples = bufsize / (cflac.info.channels * cflac.info.bitsPerSample / 8);
+ int nsamples = min (bufsamples, frame->header.blocksize);
+ char *bufptr = &buffer[remaining];
+ for (int i = 0; i < nsamples; i++) {
+ FLAC__int16 lsample = (FLAC__int16)inputbuffer[0][i];
+ ((int16_t*)bufptr)[0] = lsample;
+ bufptr += cflac.info.bitsPerSample / 8;
+ remaining += cflac.info.bitsPerSample / 8;
+ if (cflac.info.channels > 1) {
+ FLAC__int16 rsample = (FLAC__int16)inputbuffer[1][i];
+ ((int16_t*)bufptr)[0] = rsample;
+ bufptr += cflac.info.bitsPerSample / 8;
+ remaining += cflac.info.bitsPerSample / 8;
+ }
+ }
+ if (readbytes > bufsize) {
+ printf ("flac: buffer overflow, distortion will occur\n");
+ // return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void
+cflac_metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) {
+ FLAC__uint64 total_samples = metadata->data.stream_info.total_samples;
+ int sample_rate = metadata->data.stream_info.sample_rate;
+ int channels = metadata->data.stream_info.channels;
+ int bps = metadata->data.stream_info.bits_per_sample;
+ cflac.info.samplesPerSecond = sample_rate;
+ cflac.info.channels = channels;
+ cflac.info.bitsPerSample = bps;
+ cflac.info.duration = total_samples / (float)sample_rate;
+ cflac.info.position = 0;
+}
+
+void
+cflac_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) {
+ fprintf(stderr, "cflac: got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
+}
+
+int
+cflac_init (const char *fname, int track, float start, float end) {
+ printf ("cflac_init called for %s\n", fname);
+ FLAC__StreamDecoderInitStatus status;
+ decoder = FLAC__stream_decoder_new();
+ if (!decoder) {
+ printf ("FLAC__stream_decoder_new failed\n");
+ return -1;
+ }
+ FLAC__stream_decoder_set_md5_checking(decoder, 0);
+ status = FLAC__stream_decoder_init_file(decoder, fname, cflac_write_callback, cflac_metadata_callback, cflac_error_callback, NULL);
+ cflac.info.duration = -1;
+ cflac.info.position = 0;
+ FLAC__stream_decoder_process_until_end_of_metadata (decoder);
+ if (cflac.info.duration == -1) {
+ printf ("FLAC duration calculation failed\n");
+ return -1;
+ }
+ remaining = 0;
+ return 0;
+}
+
+void
+cflac_free (void) {
+ if (decoder) {
+ FLAC__stream_decoder_delete(decoder);
+ decoder = NULL;
+ }
+}
+
+int
+cflac_read (char *bytes, int size) {
+ int nsamples = size / (cflac.info.channels * cflac.info.bitsPerSample / 8);
+ do {
+ if (remaining) {
+ int sz = min (remaining, size);
+ memcpy (bytes, buffer, sz);
+ if (sz < remaining) {
+ memmove (buffer, &buffer[sz], remaining-sz);
+ }
+ remaining -= sz;
+ bytes += sz;
+ size -= sz;
+ }
+ if (!size) {
+ break;
+ }
+ if (!FLAC__stream_decoder_process_single (decoder)) {
+ memset (bytes, 0, size);
+ return -1;
+ }
+ if (FLAC__stream_decoder_get_state (decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) {
+ return -1;
+ }
+ } while (size > 0);
+ cflac.info.position += (float)nsamples / cflac.info.samplesPerSecond;
+ return 0;
+}
+
+int
+cflac_seek (float time) {
+ if (!FLAC__stream_decoder_seek_absolute (decoder, (FLAC__uint64)(time * cflac.info.samplesPerSecond))) {
+ return -1;
+ }
+ remaining = 0;
+ cflac.info.position = time;
+ return 0;
+}
+
+int
+cflac_add (const char *fname) {
+ return 0;
+}
+
+codec_t cflac = {
+ .init = cflac_init,
+ .free = cflac_free,
+ .read = cflac_read,
+ .seek = cflac_seek,
+ .add = cflac_add
+};
diff --git a/cflac.h b/cflac.h
new file mode 100644
index 00000000..752e6f2e
--- /dev/null
+++ b/cflac.h
@@ -0,0 +1,8 @@
+#ifndef __CFLAC_H
+#define __CFLAC_H
+
+extern codec_t cflac;
+
+#endif // __CFLAC_H
+
+
diff --git a/playlist.c b/playlist.c
index 30f5f1b3..0f5385a9 100644
--- a/playlist.c
+++ b/playlist.c
@@ -10,6 +10,7 @@
#include "cmod.h"
#include "cmp3.h"
#include "cgme.h"
+#include "cflac.h"
playItem_t *playlist_head;
playItem_t *playlist_tail;
@@ -47,6 +48,9 @@ ps_add_file (const char *fname) {
else if (!strcasecmp (eol, "mp3")) {
codec = &cmp3;
}
+ else if (!strcasecmp (eol, "flac")) {
+ codec = &cflac;
+ }
else if (!strcasecmp (eol, "nsf")) {
codec = &cgme;
return codec->add (fname);