diff options
author | 2009-07-07 20:26:21 +0200 | |
---|---|---|
committer | 2009-07-07 20:26:21 +0200 | |
commit | 52667820e1a76d97d0daca25b9621db86e11476d (patch) | |
tree | b36311626b262e7b8ec179d39926e84be52f56f4 | |
parent | df0bf69ac2c5ee6473e9e648dcaa1f4551a9b001 (diff) |
flac support
-rw-r--r-- | Jamfile | 4 | ||||
-rw-r--r-- | cflac.c | 141 | ||||
-rw-r--r-- | cflac.h | 8 | ||||
-rw-r--r-- | playlist.c | 4 |
4 files changed, 155 insertions, 2 deletions
@@ -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 + + @@ -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); |