[SCM] libgroove/upstream: add acoustid fingerprinter sink. closes #19
andrewrk-guest at users.alioth.debian.org
andrewrk-guest at users.alioth.debian.org
Sat Apr 19 22:37:15 UTC 2014
The following commit has been merged in the upstream branch:
commit ac4c373bfefe680fb13a7ce56ff3f62cf6d63e96
Author: Andrew Kelley <superjoe30 at gmail.com>
Date: Sat Apr 19 01:49:12 2014 -0700
add acoustid fingerprinter sink. closes #19
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4dd375a..616f15f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,6 +30,15 @@ else(DISABLE_LOUDNESS)
file(GLOB_RECURSE LIBGROOVE_LOUDNESS_HEADERS ${CMAKE_SOURCE_DIR}/grooveloudness/*.h)
endif(DISABLE_LOUDNESS)
+if(DISABLE_FINGERPRINTER)
+ set(LIBGROOVE_FINGERPRINTER_STATUS "no")
+else(DISABLE_FINGERPRINTER)
+ set(LIBGROOVE_FINGERPRINTER_STATUS "yes")
+ message("Configuring libgroovefingerprinter version ${LIBGROOVE_VERSION}")
+ file(GLOB_RECURSE LIBGROOVE_FINGERPRINTER_SOURCES ${CMAKE_SOURCE_DIR}/groovefingerprinter/*.c)
+ file(GLOB_RECURSE LIBGROOVE_FINGERPRINTER_HEADERS ${CMAKE_SOURCE_DIR}/groovefingerprinter/*.h)
+endif(DISABLE_FINGERPRINTER)
+
# check for C99
find_package(C99)
if(C99_FLAG_DETECTED)
@@ -63,6 +72,18 @@ else(DISABLE_LOUDNESS)
endif(EBUR128_FOUND)
endif(DISABLE_LOUDNESS)
+# check for chromaprint
+if(DISABLE_FINGERPRINTER)
+ set(STATUS_CHROMAPRINT, "not needed")
+else(DISABLE_FINGERPRINTER)
+ find_package(Chromaprint)
+ if(CHROMAPRINT_FOUND)
+ set(STATUS_CHROMAPRINT "OK")
+ else(CHROMAPRINT_FOUND)
+ set(STATUS_CHROMAPRINT "not found")
+ endif(CHROMAPRINT_FOUND)
+endif(DISABLE_FINGERPRINTER)
+
# check for SDL2
if(DISABLE_PLAYER)
set(STATUS_SDL2 "not needed")
@@ -379,6 +400,42 @@ else()
add_dependencies(replaygain groove grooveloudness)
endif()
+if(DISABLE_FINGERPRINTER)
+else()
+ add_library(groovefingerprinter SHARED
+ ${LIBGROOVE_FINGERPRINTER_SOURCES}
+ ${LIBGROOVE_FINGERPRINTER_HEADERS})
+ set_target_properties(groovefingerprinter PROPERTIES
+ SOVERSION ${LIBGROOVE_VERSION_MAJOR}
+ VERSION ${LIBGROOVE_VERSION}
+ COMPILE_FLAGS ${LIB_CFLAGS}
+ )
+ target_link_libraries(groovefingerprinter LINK_PUBLIC groove ${CMAKE_THREAD_LIBS_INIT})
+ add_dependencies(groovefingerprinter groove)
+ target_link_libraries(groovefingerprinter LINK_PRIVATE ${CHROMAPRINT_LIBRARIES})
+ include_directories(${CHROMAPRINT_INCLUDE_DIR})
+
+ install(FILES "groovefingerprinter/fingerprinter.h" DESTINATION "include/groovefingerprinter")
+ install(TARGETS groovefingerprinter DESTINATION lib)
+
+
+ add_library(groovefingerprinter_static STATIC
+ ${LIBGROOVE_FINGERPRINTER_SOURCES}
+ ${LIBGROOVE_FINGERPRINTER_HEADERS})
+ set_target_properties(groovefingerprinter_static PROPERTIES
+ OUTPUT_NAME groovefingerprinter
+ COMPILE_FLAGS "${LIB_CFLAGS} -fPIC")
+ install(TARGETS groovefingerprinter_static DESTINATION lib)
+
+
+ add_executable(fingerprint example/fingerprint.c)
+ set_target_properties(fingerprint PROPERTIES
+ COMPILE_FLAGS ${EXAMPLE_CFLAGS})
+ include_directories(${EXAMPLE_INCLUDES})
+ target_link_libraries(fingerprint groove groovefingerprinter)
+ add_dependencies(fingerprint groove groovefingerprinter)
+endif()
+
message("\n"
"Installation Summary\n"
"--------------------\n"
@@ -386,6 +443,7 @@ message("\n"
"* Build libgroove : ${LIBGROOVE_STATUS}\n"
"* Build libgrooveplayer : ${LIBGROOVE_PLAYER_STATUS}\n"
"* Build libgrooveloudness : ${LIBGROOVE_LOUDNESS_STATUS}\n"
+"* Build libgroovefingerprinter : ${LIBGROOVE_FINGERPRINTER_STATUS}\n"
)
message(
@@ -403,6 +461,7 @@ message(
"* threads : ${STATUS_THREADS}\n"
"* SDL2 : ${STATUS_SDL2}\n"
"* ebur128 : ${STATUS_EBUR128}\n"
+"* chromaprint : ${STATUS_CHROMAPRINT}\n"
"* libavformat : ${STATUS_LIBAVFORMAT}\n"
"* libavcodec : ${STATUS_LIBAVCODEC}\n"
"* libavfilter : ${STATUS_LIBAVFILTER}\n"
diff --git a/README.md b/README.md
index e19d446..fc3682b 100644
--- a/README.md
+++ b/README.md
@@ -24,14 +24,15 @@ music player.
* **loudness scanner sink** - uses the [EBU R 128](http://tech.ebu.ch/loudness)
standard to detect loudness. The values it produces are compatible with
[ReplayGain](http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification).
- * ([on the roadmap](https://github.com/andrewrk/libgroove/issues/19)) accoustid fingerprint
+ * **fingerprint sink** - uses [chromaprint](acoustid.org/chromaprint) to
+ generate unique song IDs that can be used with the acoustid service.
* Thread-safe.
* Example programs included:
* `playlist` - play a series of songs with gapless playback
* `metadata` - read or update song metadata
* `replaygain` - report the suggested replaygain for a set of files
* `transcode` - transcode one or more files into one output file
- * Cross-platform.
+ * `fingerprint` - generate acoustid fingerprints for one or more files
## Dependencies
@@ -45,6 +46,7 @@ so that you can still compile if they cannot be found on your system.
- [libmp3lame-dev](http://lame.sourceforge.net/)
* [libebur128](https://github.com/jiixyj/libebur128) (bundled)
* [libsdl2-dev](http://www.libsdl.org/) (bundled)
+ * [libchromaprint-dev](http://acoustid.org/chromaprint)
## Installation
@@ -55,7 +57,7 @@ so that you can still compile if they cannot be found on your system.
```
sudo apt-add-repository ppa:andrewrk/libgroove
sudo apt-get update
- sudo apt-get install libgroove-dev libgrooveplayer-dev libgrooveloudness-dev
+ sudo apt-get install libgroove-dev libgrooveplayer-dev libgrooveloudness-dev libgroovefingerprinter-dev
```
* [Debian experimental](http://serverfault.com/questions/22414)
@@ -69,9 +71,9 @@ so that you can still compile if they cannot be found on your system.
## Documentation
* Check out the example programs in the example folder.
- * Read some header files for the relevant APIs:
+ * Read header files for the relevant APIs:
* groove/groove.h
- - global stuff
+ - globals
- GrooveFile
- GroovePlaylist
- GrooveBuffer
@@ -82,6 +84,8 @@ so that you can still compile if they cannot be found on your system.
- GroovePlayer
* grooveloudness/loudness.h
- GrooveLoudnessDetector
+ * groovefingerprinter/fingerprinter.h
+ - GrooveFingerprinter
* Join #libgroove on irc.freenode.org and ask questions.
## Projects Using libgroove
diff --git a/cmake/FindChromaprint.cmake b/cmake/FindChromaprint.cmake
new file mode 100644
index 0000000..5b093de
--- /dev/null
+++ b/cmake/FindChromaprint.cmake
@@ -0,0 +1,22 @@
+# copied from https://bitbucket.org/acoustid/acoustid-fingerprinter
+# GPLv2 license
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE(PkgConfig)
+PKG_CHECK_MODULES(PKG_LIBCHROMAPRINT libchromaprint)
+
+FIND_PATH(CHROMAPRINT_INCLUDE_DIR chromaprint.h
+ ${PKG_LIBCHROMAPRINT_INCLUDE_DIRS}
+ /usr/include
+ /usr/local/include
+)
+
+FIND_LIBRARY(CHROMAPRINT_LIBRARIES
+ NAMES
+ chromaprint chromaprint.dll
+ PATHS
+ ${PKG_LIBCHROMAPRINT_LIBRARY_DIRS}
+ /usr/lib
+ /usr/local/lib
+)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Chromaprint DEFAULT_MSG CHROMAPRINT_LIBRARIES CHROMAPRINT_INCLUDE_DIR)
diff --git a/example/fingerprint.c b/example/fingerprint.c
new file mode 100644
index 0000000..4172004
--- /dev/null
+++ b/example/fingerprint.c
@@ -0,0 +1,59 @@
+/* compute the acoustid of a list of songs */
+
+#include <groovefingerprinter/fingerprinter.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char * argv[]) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s file1 file2 ...\n", argv[0]);
+ return 1;
+ }
+
+ groove_init();
+ atexit(groove_finish);
+ groove_set_logging(GROOVE_LOG_INFO);
+
+ struct GroovePlaylist *playlist = groove_playlist_create();
+
+ for (int i = 1; i < argc; i += 1) {
+ char * filename = argv[i];
+ struct GrooveFile * file = groove_file_open(filename);
+ if (!file) {
+ fprintf(stderr, "Unable to open %s\n", filename);
+ continue;
+ }
+ groove_playlist_insert(playlist, file, 1.0, NULL);
+ }
+
+ struct GrooveFingerprinter *printer = groove_fingerprinter_create();
+ groove_fingerprinter_attach(printer, playlist);
+
+ struct GrooveFingerprinterInfo info;
+ while (groove_fingerprinter_info_get(printer, &info, 1) == 1) {
+ if (info.item) {
+ fprintf(stdout, "\nduration: %f: %s\n",
+ info.duration,
+ info.item->file->filename);
+ fprintf(stdout, "%s\n", info.fingerprint);
+ groove_fingerprinter_free_info(&info);
+ } else {
+ break;
+ }
+ }
+
+ struct GroovePlaylistItem *item = playlist->head;
+ while (item) {
+ struct GrooveFile *file = item->file;
+ struct GroovePlaylistItem *next = item->next;
+ groove_playlist_remove(playlist, item);
+ groove_file_close(file);
+ item = next;
+ }
+
+ groove_fingerprinter_detach(printer);
+ groove_fingerprinter_destroy(printer);
+ groove_playlist_destroy(playlist);
+
+ return 0;
+}
diff --git a/groovefingerprinter/fingerprinter.c b/groovefingerprinter/fingerprinter.c
new file mode 100644
index 0000000..3907f5c
--- /dev/null
+++ b/groovefingerprinter/fingerprinter.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2013 Andrew Kelley
+ *
+ * This file is part of libgroove, which is MIT licensed.
+ * See http://opensource.org/licenses/MIT
+ */
+
+#include "fingerprinter.h"
+#include <groove/queue.h>
+
+#include <chromaprint.h>
+
+#include <libavutil/mem.h>
+#include <libavutil/log.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+struct GrooveFingerprinterPrivate {
+ struct GrooveFingerprinter externals;
+
+ int state_history_count;
+
+ // index into all_track_states
+ struct GrooveSink *sink;
+ struct GrooveQueue *info_queue;
+ pthread_t thread_id;
+
+ // info_head_mutex applies to variables inside this block.
+ pthread_mutex_t info_head_mutex;
+ char info_head_mutex_inited;
+ // current playlist item pointer
+ struct GroovePlaylistItem *info_head;
+ double info_pos;
+ // analyze_thread waits on this when the info queue is full
+ pthread_cond_t drain_cond;
+ char drain_cond_inited;
+ // how many items are in the queue
+ int info_queue_count;
+ double track_duration;
+ double album_duration;
+
+ ChromaprintContext *chroma_ctx;
+
+ // set temporarily
+ struct GroovePlaylistItem *purge_item;
+
+ int abort_request;
+};
+
+static int emit_track_info(struct GrooveFingerprinterPrivate *p) {
+ struct GrooveFingerprinterInfo *info = av_mallocz(sizeof(struct GrooveFingerprinterInfo));
+ if (!info) {
+ av_log(NULL, AV_LOG_ERROR, "unable to allocate fingerprinter info\n");
+ return -1;
+ }
+ info->item = p->info_head;
+ info->duration = p->track_duration;
+
+ chromaprint_finish(p->chroma_ctx);
+ chromaprint_get_fingerprint(p->chroma_ctx, &info->fingerprint);
+
+ groove_queue_put(p->info_queue, info);
+
+ return 0;
+}
+
+static void *print_thread(void *arg) {
+ struct GrooveFingerprinterPrivate *p = arg;
+ struct GrooveFingerprinter *printer = &p->externals;
+
+ struct GrooveBuffer *buffer;
+ while (!p->abort_request) {
+ pthread_mutex_lock(&p->info_head_mutex);
+
+ if (p->info_queue_count >= printer->info_queue_size) {
+ pthread_cond_wait(&p->drain_cond, &p->info_head_mutex);
+ pthread_mutex_unlock(&p->info_head_mutex);
+ continue;
+ }
+
+ // we definitely want to unlock the mutex while we wait for the
+ // next buffer. Otherwise there will be a deadlock when sink_flush or
+ // sink_purge is called.
+ pthread_mutex_unlock(&p->info_head_mutex);
+
+ int result = groove_sink_buffer_get(p->sink, &buffer, 1);
+
+ pthread_mutex_lock(&p->info_head_mutex);
+
+ if (result == GROOVE_BUFFER_END) {
+ // last file info
+ emit_track_info(p);
+
+ // send album info
+ struct GrooveFingerprinterInfo *info = av_mallocz(
+ sizeof(struct GrooveFingerprinterInfo));
+ if (info) {
+ info->duration = p->album_duration;
+ groove_queue_put(p->info_queue, info);
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "unable to allocate album fingerprint info\n");
+ }
+
+ p->album_duration = 0.0;
+
+ p->info_head = NULL;
+ p->info_pos = -1.0;
+
+ pthread_mutex_unlock(&p->info_head_mutex);
+ continue;
+ }
+
+ if (result != GROOVE_BUFFER_YES) {
+ pthread_mutex_unlock(&p->info_head_mutex);
+ break;
+ }
+
+ if (buffer->item != p->info_head) {
+ if (p->info_head) {
+ emit_track_info(p);
+ }
+ chromaprint_start(p->chroma_ctx, 44100, 2);
+ p->track_duration = 0.0;
+ p->info_head = buffer->item;
+ p->info_pos = buffer->pos;
+ }
+
+ double buffer_duration = buffer->frame_count / (double)buffer->format.sample_rate;
+ p->track_duration += buffer_duration;
+ p->album_duration += buffer_duration;
+ chromaprint_feed(p->chroma_ctx, buffer->data[0], buffer->frame_count * 2);
+
+ pthread_mutex_unlock(&p->info_head_mutex);
+ groove_buffer_unref(buffer);
+ }
+
+ return NULL;
+}
+
+static void info_queue_cleanup(struct GrooveQueue* queue, void *obj) {
+ struct GrooveFingerprinterInfo *info = obj;
+ struct GrooveFingerprinterPrivate *p = queue->context;
+ p->info_queue_count -= 1;
+ av_free(info);
+}
+
+static void info_queue_put(struct GrooveQueue *queue, void *obj) {
+ struct GrooveFingerprinterPrivate *p = queue->context;
+ p->info_queue_count += 1;
+}
+
+static void info_queue_get(struct GrooveQueue *queue, void *obj) {
+ struct GrooveFingerprinterPrivate *p = queue->context;
+ struct GrooveFingerprinter *printer = &p->externals;
+
+ p->info_queue_count -= 1;
+
+ if (p->info_queue_count < printer->info_queue_size)
+ pthread_cond_signal(&p->drain_cond);
+}
+
+static int info_queue_purge(struct GrooveQueue* queue, void *obj) {
+ struct GrooveFingerprinterInfo *info = obj;
+ struct GrooveFingerprinterPrivate *p = queue->context;
+
+ return info->item == p->purge_item;
+}
+
+static void sink_purge(struct GrooveSink *sink, struct GroovePlaylistItem *item) {
+ struct GrooveFingerprinterPrivate *p = sink->userdata;
+
+ pthread_mutex_lock(&p->info_head_mutex);
+ p->purge_item = item;
+ groove_queue_purge(p->info_queue);
+ p->purge_item = NULL;
+
+ if (p->info_head == item) {
+ p->info_head = NULL;
+ p->info_pos = -1.0;
+ }
+ pthread_cond_signal(&p->drain_cond);
+ pthread_mutex_unlock(&p->info_head_mutex);
+}
+
+static void sink_flush(struct GrooveSink *sink) {
+ struct GrooveFingerprinterPrivate *p = sink->userdata;
+
+ pthread_mutex_lock(&p->info_head_mutex);
+ groove_queue_flush(p->info_queue);
+ p->track_duration = 0.0;
+ p->info_head = NULL;
+ p->info_pos = -1.0;
+
+ pthread_cond_signal(&p->drain_cond);
+ pthread_mutex_unlock(&p->info_head_mutex);
+}
+
+struct GrooveFingerprinter *groove_fingerprinter_create(void) {
+ struct GrooveFingerprinterPrivate *p = av_mallocz(sizeof(struct GrooveFingerprinterPrivate));
+ if (!p) {
+ av_log(NULL, AV_LOG_ERROR, "unable to allocate fingerprinter\n");
+ return NULL;
+ }
+
+ struct GrooveFingerprinter *printer = &p->externals;
+
+ if (pthread_mutex_init(&p->info_head_mutex, NULL) != 0) {
+ groove_fingerprinter_destroy(printer);
+ av_log(NULL, AV_LOG_ERROR, "unable to create mutex\n");
+ return NULL;
+ }
+ p->info_head_mutex_inited = 1;
+
+ if (pthread_cond_init(&p->drain_cond, NULL) != 0) {
+ groove_fingerprinter_destroy(printer);
+ av_log(NULL, AV_LOG_ERROR, "unable to create mutex condition\n");
+ return NULL;
+ }
+ p->drain_cond_inited = 1;
+
+ p->info_queue = groove_queue_create();
+ if (!p->info_queue) {
+ groove_fingerprinter_destroy(printer);
+ av_log(NULL, AV_LOG_ERROR, "unable to allocate queue\n");
+ return NULL;
+ }
+ p->info_queue->context = printer;
+ p->info_queue->cleanup = info_queue_cleanup;
+ p->info_queue->put = info_queue_put;
+ p->info_queue->get = info_queue_get;
+ p->info_queue->purge = info_queue_purge;
+
+ p->sink = groove_sink_create();
+ if (!p->sink) {
+ groove_fingerprinter_destroy(printer);
+ av_log(NULL, AV_LOG_ERROR, "unable to allocate sink\n");
+ return NULL;
+ }
+ p->sink->audio_format.sample_rate = 44100;
+ p->sink->audio_format.channel_layout = GROOVE_CH_LAYOUT_STEREO;
+ p->sink->audio_format.sample_fmt = GROOVE_SAMPLE_FMT_S16;
+ p->sink->userdata = printer;
+ p->sink->purge = sink_purge;
+ p->sink->flush = sink_flush;
+
+ // set some defaults
+ printer->info_queue_size = INT_MAX;
+ printer->sink_buffer_size = p->sink->buffer_size;
+
+ return printer;
+}
+
+void groove_fingerprinter_destroy(struct GrooveFingerprinter *printer) {
+ if (!printer)
+ return;
+
+ struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
+
+ if (p->sink)
+ groove_sink_destroy(p->sink);
+
+ if (p->info_queue)
+ groove_queue_destroy(p->info_queue);
+
+ if (p->info_head_mutex_inited)
+ pthread_mutex_destroy(&p->info_head_mutex);
+
+ if (p->drain_cond_inited)
+ pthread_cond_destroy(&p->drain_cond);
+
+ av_free(p);
+}
+
+int groove_fingerprinter_attach(struct GrooveFingerprinter *printer,
+ struct GroovePlaylist *playlist)
+{
+ struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
+
+ printer->playlist = playlist;
+ groove_queue_reset(p->info_queue);
+
+ p->chroma_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
+
+ if (groove_sink_attach(p->sink, playlist) < 0) {
+ groove_fingerprinter_detach(printer);
+ av_log(NULL, AV_LOG_ERROR, "unable to attach sink\n");
+ return -1;
+ }
+
+ if (pthread_create(&p->thread_id, NULL, print_thread, printer) != 0) {
+ groove_fingerprinter_detach(printer);
+ av_log(NULL, AV_LOG_ERROR, "unable to create printer thread\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int groove_fingerprinter_detach(struct GrooveFingerprinter *printer) {
+ struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
+
+ p->abort_request = 1;
+ groove_sink_detach(p->sink);
+ groove_queue_flush(p->info_queue);
+ groove_queue_abort(p->info_queue);
+ pthread_cond_signal(&p->drain_cond);
+ pthread_join(p->thread_id, NULL);
+
+ printer->playlist = NULL;
+
+ if (p->chroma_ctx) {
+ chromaprint_free(p->chroma_ctx);
+ p->chroma_ctx = NULL;
+ }
+
+ p->abort_request = 0;
+ p->info_head = NULL;
+ p->info_pos = 0;
+ p->track_duration = 0.0;
+
+ return 0;
+}
+
+int groove_fingerprinter_info_get(struct GrooveFingerprinter *printer,
+ struct GrooveFingerprinterInfo *info, int block)
+{
+ struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
+
+ struct GrooveFingerprinterInfo *info_ptr;
+ if (groove_queue_get(p->info_queue, (void**)&info_ptr, block) == 1) {
+ *info = *info_ptr;
+ av_free(info_ptr);
+ return 1;
+ }
+
+ return 0;
+}
+
+int groove_fingerprinter_info_peek(struct GrooveFingerprinter *printer,
+ int block)
+{
+ struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
+ return groove_queue_peek(p->info_queue, block);
+}
+
+void groove_fingerprinter_position(struct GrooveFingerprinter *printer,
+ struct GroovePlaylistItem **item, double *seconds)
+{
+ struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
+
+ pthread_mutex_lock(&p->info_head_mutex);
+
+ if (item)
+ *item = p->info_head;
+
+ if (seconds)
+ *seconds = p->info_pos;
+
+ pthread_mutex_unlock(&p->info_head_mutex);
+}
+
+void groove_fingerprinter_free_info(struct GrooveFingerprinterInfo *info) {
+ if (!info->fingerprint) return;
+ chromaprint_dealloc((void*)info->fingerprint);
+ info->fingerprint = NULL;
+}
+
+int groove_fingerprinter_encode(void *fp, int size, char **encoded_fp) {
+ int encoded_size;
+ return chromaprint_encode_fingerprint(fp, size,
+ CHROMAPRINT_ALGORITHM_DEFAULT, (void*)encoded_fp, &encoded_size, 1);
+}
+
+int groove_fingerprinter_decode(char *encoded_fp, void **fp, int *size) {
+ int algorithm;
+ int encoded_size = strlen(encoded_fp);
+ return chromaprint_decode_fingerprint(encoded_fp, encoded_size, fp, size,
+ &algorithm, 1);
+}
+
+void groove_fingerprinter_dealloc(void *ptr) {
+ if (!ptr) return;
+ chromaprint_dealloc(ptr);
+}
diff --git a/groovefingerprinter/fingerprinter.h b/groovefingerprinter/fingerprinter.h
new file mode 100644
index 0000000..2fe6e9a
--- /dev/null
+++ b/groovefingerprinter/fingerprinter.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013 Andrew Kelley
+ *
+ * This file is part of libgroove, which is MIT licensed.
+ * See http://opensource.org/licenses/MIT
+ */
+
+#ifndef GROOVE_FINGERPRINTER_H_INCLUDED
+#define GROOVE_FINGERPRINTER_H_INCLUDED
+
+#include <groove/groove.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/* use this to find out the unique id of an audio track */
+
+struct GrooveFingerprinterInfo {
+ /* Compressed string. */
+ char *fingerprint;
+ /* how many seconds long this song is */
+ double duration;
+
+ /* the playlist item that this info applies to.
+ * When this is NULL this is the end-of-playlist sentinel and
+ * other properties are undefined.
+ */
+ struct GroovePlaylistItem *item;
+};
+
+struct GrooveFingerprinter {
+ /* maximum number of GrooveFingerprinterInfo items to store in this
+ * fingerprinter's queue. this defaults to MAX_INT, meaning that
+ * the fingerprinter will cause the decoder to decode the entire
+ * playlist. if you want to instead, for example, obtain fingerprints
+ * at the same time as playback, you might set this value to 1.
+ */
+ int info_queue_size;
+
+ /* how big the sink buffer should be, in sample frames.
+ * groove_fingerprinter_create defaults this to 8192
+ */
+ int sink_buffer_size;
+
+ /* read-only. set when attached and cleared when detached */
+ struct GroovePlaylist *playlist;
+};
+
+struct GrooveFingerprinter *groove_fingerprinter_create(void);
+void groove_fingerprinter_destroy(struct GrooveFingerprinter *printer);
+
+/* once you attach, you must detach before destroying the playlist */
+int groove_fingerprinter_attach(struct GrooveFingerprinter *printer,
+ struct GroovePlaylist *playlist);
+int groove_fingerprinter_detach(struct GrooveFingerprinter *printer);
+
+/* returns < 0 on error, 0 on aborted (block=1) or no info ready (block=0),
+ * 1 on info returned.
+ * When you get info you must free it with groove_fingerprinter_free_info.
+ */
+int groove_fingerprinter_info_get(struct GrooveFingerprinter *printer,
+ struct GrooveFingerprinterInfo *info, int block);
+
+void groove_fingerprinter_free_info(struct GrooveFingerprinterInfo *info);
+
+/* returns < 0 on error, 0 on no info ready, 1 on info ready
+ * if block is 1, block until info is ready
+ */
+int groove_fingerprinter_info_peek(struct GrooveFingerprinter *printer,
+ int block);
+
+/* get the position of the printer head
+ * both the current playlist item and the position in seconds in the playlist
+ * item are given. item will be set to NULL if the playlist is empty
+ * you may pass NULL for item or seconds
+ */
+void groove_fingerprinter_position(struct GrooveFingerprinter *printer,
+ struct GroovePlaylistItem **item, double *seconds);
+
+/**
+ * Compress and base64-encode a raw fingerprint
+ *
+ * The caller is responsible for freeing the returned pointer using
+ * groove_fingerprinter_dealloc().
+ *
+ * Parameters:
+ * - fp: pointer to an array of unsigned 32-bit integers representing the raw
+ * fingerprint to be encoded
+ * - size: number of items in the raw fingerprint
+ * - encoded_fp: pointer to a pointer, where the encoded fingerprint will be
+ * stored
+ *
+ * Returns:
+ * - 0 on error, 1 on success
+ */
+int groove_fingerprinter_encode(void *fp, int size, char **encoded_fp);
+
+/**
+ * Uncompress and base64-decode an encoded fingerprint
+ *
+ * The caller is responsible for freeing the returned pointer using
+ * groove_fingerprinter_dealloc().
+ *
+ * Parameters:
+ * - encoded_fp: Pointer to an encoded fingerprint
+ * - encoded_size: Size of the encoded fingerprint in bytes
+ * - fp: Pointer to a pointer, where the decoded raw fingerprint (array
+ * of unsigned 32-bit integers) will be stored
+ * - size: Number of items in the returned raw fingerprint
+ *
+ * Returns:
+ * - 0 on error, 1 on success
+ */
+int groove_fingerprinter_decode(char *encoded_fp, void **fp, int *size);
+
+void groove_fingerprinter_dealloc(void *ptr);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GROOVE_FINGERPRINTER_H_INCLUDED */
diff --git a/grooveloudness/loudness.h b/grooveloudness/loudness.h
index 3f45dc4..30f0d57 100644
--- a/grooveloudness/loudness.h
+++ b/grooveloudness/loudness.h
@@ -8,13 +8,13 @@
#ifndef GROOVE_LOUDNESS_H_INCLUDED
#define GROOVE_LOUDNESS_H_INCLUDED
+#include <groove/groove.h>
+
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
-#include <groove/groove.h>
-
struct GrooveLoudnessDetectorInfo {
/* loudness is in LUFS. 1 LUFS == 1 dB
* EBU R128 specifies that playback should target -23 LUFS. replaygain on
diff --git a/grooveplayer/player.h b/grooveplayer/player.h
index cf0bdea..5104ef2 100644
--- a/grooveplayer/player.h
+++ b/grooveplayer/player.h
@@ -8,13 +8,13 @@
#ifndef GROOVE_PLAYER_H_INCLUDED
#define GROOVE_PLAYER_H_INCLUDED
+#include <groove/groove.h>
+
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
-#include <groove/groove.h>
-
/* use this to make a playlist utilize your speakers */
enum GroovePlayerEventType {
--
libgroove packaging
More information about the pkg-multimedia-commits
mailing list