Remove unused bits from 3rdparty/chromaprint

This commit is contained in:
David Sansome 2012-01-07 15:12:26 +00:00
parent e1804219dc
commit 665b721236
56 changed files with 0 additions and 3796 deletions

View File

@ -1,5 +0,0 @@
Version 0.1 (2010-10-30)
========================
- Initial release.

View File

@ -39,29 +39,10 @@ set(BIN_INSTALL_DIR ${EXEC_INSTALL_PREFIX}/bin CACHE PATH "Installation prefix f
set(LIB_INSTALL_DIR ${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX} CACHE PATH "Installation prefix for object code libraries" FORCE)
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Installation prefix for C header files" FORCE)
if(APPLE)
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
endif()
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(BUILD_EXAMPLES "Build the examples" OFF)
option(BUILD_TESTS "Build the test suite" OFF)
option(BUILD_TOOLS "Build standard tools" OFF)
option(BUILD_EXTRA_TOOLS "Build extra tools (only useful for development of this library)" OFF)
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
endif()
if(CMAKE_COMPILER_IS_GNUCXX AND BUILD_SHARED_LIBS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
endif()
if(NOT BUILD_SHARED_LIBS)
add_definitions(-DCHROMAPRINT_NODLL)
endif()
option(WITH_AVFFT "Use FFmpeg for FFT calculations" OFF)
option(WITH_FFTW3 "Use FFTW3 for FFT calculations" OFF)
@ -123,36 +104,7 @@ if(WITH_FFTW3)
message(STATUS "Using FFTW3 for FFT calculations")
endif(WITH_FFTW3)
if(NOT APPLE AND NOT BUILD_FRAMEWORK)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libchromaprint.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libchromaprint.pc)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libchromaprint.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
add_subdirectory(src)
if(BUILD_TOOLS_EXTRA)
find_package(PNG REQUIRED)
endif(BUILD_TOOLS_EXTRA)
find_package(Boost COMPONENTS system filesystem)
if(BUILD_TOOLS OR BUILD_TOOLS_EXTRA OR BUILD_EXAMPLES)
find_package(FFmpeg REQUIRED)
endif()
if(BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
if(BUILD_TOOLS OR BUILD_TOOLS_EXTRA)
find_package(Taglib REQUIRED)
add_subdirectory(tools)
endif(BUILD_TOOLS OR BUILD_TOOLS_EXTRA)
if(BUILD_TESTS)
find_package(Threads)
find_package(GTest REQUIRED)
add_subdirectory(tests)
endif(BUILD_TESTS)

View File

@ -1,44 +0,0 @@
Version 0.6 -- December 22, 2011
================================
- Support for 24-bit file formats in fpcalc.
- The fpcalc utility now uses 120 seconds of audio data by default.
- Python bindings moved to a separate project (pyacoustid).
Version 0.5 -- October 6, 2011
==============================
- Unicode command line handling in fpcalc.
- Fixed a crash in fpcalc when FFmpeg was not able to identify the codec.
- Added encode_fingerprint to the Python bindings.
Version 0.4 -- May 14, 2011
===========================
- Support for building a Mac OS X framework.
- Support for building a static library.
- Simple C example (fpcalc) that can be used from external applications for
fingerprint calculations.
Version 0.3 -- April 26, 2011
=============================
- Fixed compilation with MSVC 2010.
- Added support for calculating FFT using the Accelerate framework on
Mac OS X and iOS.
- Added Python bindings.
Version 0.2 -- January 26, 2011
===============================
- New public functions chromaprint_{encode,decode}_fingerprint to
encoding/decoding raw fingerprints.
- New public function chromaprint_dealloc that should be used for
releasing all memory allocated in Chromaprint functions.
- Extended fpcollect to allow processing files with MBIDs.
Version 0.1 -- October 30, 2010
===============================
- Initial release

View File

@ -1,96 +0,0 @@
Chromaprint
===========
Dependencies
------------
The library itself only depends on a FFT library, which at the moment can
be either FFmpeg [1] (at least r22291, 0.6 is fine), FFTW3 [2] or if you are
on iOS or OS X, you can use the Accelerate/vDSP framework. See the next
section for details.
The tools included in the package require FFmpeg (can be older), TagLib [3]
and Boost Filesystem [4].
In order to build the test suite, you will need the Google Test library [5].
[1] http://www.ffmpeg.org/
[2] http://www.fftw.org/
[3] http://developer.kde.org/~wheeler/taglib.html
[4] http://www.boost.org/
[5] http://code.google.com/p/googletest/
Installing
----------
The most common way to build Chromaprint is like this:
$ cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON .
$ make
$ sudo make install
This will build Chromaprint as a shared library and also include the fpcalc
utility (which is used by MusicBrainz Picard, for example).
See below for other options.
FFT Library
-----------
Chromaprint can use three FFT libraries, FFmpeg, FFTW3 and vDSP. FFmpeg is
preffered, as it's a little faster for our purposes and it's LGPL-licensed,
so it doesn't impact the license of Chromaprint. The FFT interface was added
only recently though, so it might not be available in Linux distributions yet.
FFTW3 can be used in this case, but this library is released under the GPL
license, which makes also the resulting Chromaprint binary GPL licensed.
If you run simple `cmake .`, it will try to find both FFmpeg and FFTW3 and
select the first one it finds. If you have new FFmpeg installed in a separate
location, you can let CMake know using the `FFMPEG_ROOT` option:
$ cmake -DFFMPEG_ROOT=/path/to/local/ffmpeg/install .
If you have new FFmpeg installed, but for some reason prefer to use FFTW3, you
can use the `WITH_FFTW3` option:
$ cmake -DWITH_FFTW3=ON .
There is also a `WITH_AVFFT` option, but the script will select the FFmpeg FFT
automatically if it's available, so it shouldn't be necessary to use it.
If you are on Mac, you can use the standard Accelerate framework with the vDSP
library. This requires you to install no external libraries. It will use
vDSP by default on OS X (but there still is a `WITH_VDSP` option).
Unit Tests
----------
The test suite can be built and run using the following commands:
$ cmake -DBUILD_TESTS=ON .
$ make check
Related Projects
----------------
* pyacoustid - https://github.com/sampsyo/pyacoustid
* gst-chromaprint - https://github.com/lalinsky/gst-chromaprint
Standing on the Shoulder of Giants
----------------------------------
I've learned a lot while working on this project, which would not be possible
without having information from past research. I've read many papers, but the
concrete ideas implemented in this library are based on the following papers:
* Yan Ke, Derek Hoiem, Rahul Sukthankar. Computer Vision for Music
Identification, Proceedings of Computer Vision and Pattern Recognition,
2005. http://www.cs.cmu.edu/~yke/musicretrieval/
* Frank Kurth, Meinard Müller. Efficient Index-Based Audio Matching, 2008.
http://dx.doi.org/10.1109/TASL.2007.911552
* Dalwon Jang, Chang D. Yoo, Sunil Lee, Sungwoong Kim, Ton Kalker.
Pairwise Boosted Audio Fingerprint, 2009.
http://dx.doi.org/10.1109/TIFS.2009.2034452

View File

@ -1,39 +0,0 @@
set(EXTRA_LIBS)
if(APPLE)
set(EXTRA_LIBS ${EXTRA_LIBS} -lz)
endif()
if(UNIX)
set(EXTRA_LIBS ${EXTRA_LIBS} -lpthread)
endif()
set(CMAKE_REQUIRED_LIBRARIES
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES}
${EXTRA_LIBS})
check_function_exists(av_audio_convert HAVE_AV_AUDIO_CONVERT)
if(HAVE_AV_AUDIO_CONVERT)
add_definitions(-DHAVE_AV_AUDIO_CONVERT)
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../src
${FFMPEG_LIBAVCODEC_INCLUDE_DIRS}
${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}
${FFMPEG_LIBAVUTIL_INCLUDE_DIRS}
)
add_executable(fpcalc fpcalc.c)
target_link_libraries(fpcalc chromaprint
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES}
${EXTRA_LIBS})
install(TARGETS fpcalc
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
)

View File

@ -1,118 +0,0 @@
/*
* audio conversion
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2008 Peter Ross
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_AUDIOCONVERT_H
#define AVCODEC_AUDIOCONVERT_H
/**
* @file
* Audio format conversion routines
*/
#include "libavcodec/avcodec.h"
#include "samplefmt.h"
#if FF_API_OLD_SAMPLE_FMT
/**
* @deprecated Use av_get_sample_fmt_string() instead.
*/
attribute_deprecated
void avcodec_sample_fmt_string(char *buf, int buf_size, int sample_fmt);
/**
* @deprecated Use av_get_sample_fmt_name() instead.
*/
attribute_deprecated
const char *avcodec_get_sample_fmt_name(int sample_fmt);
/**
* @deprecated Use av_get_sample_fmt() instead.
*/
attribute_deprecated
enum AVSampleFormat avcodec_get_sample_fmt(const char* name);
#endif
#if FF_API_OLD_AUDIOCONVERT
/**
* @deprecated Use av_get_channel_layout() instead.
*/
attribute_deprecated
int64_t avcodec_get_channel_layout(const char *name);
/**
* @deprecated Use av_get_channel_layout_string() instead.
*/
attribute_deprecated
void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout);
/**
* @deprecated Use av_get_channel_layout_nb_channels() instead.
*/
attribute_deprecated
int avcodec_channel_layout_num_channels(int64_t channel_layout);
#endif
/**
* Guess the channel layout
* @param nb_channels
* @param codec_id Codec identifier, or CODEC_ID_NONE if unknown
* @param fmt_name Format name, or NULL if unknown
* @return Channel layout mask
*/
uint64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name);
struct AVAudioConvert;
typedef struct AVAudioConvert AVAudioConvert;
/**
* Create an audio sample format converter context
* @param out_fmt Output sample format
* @param out_channels Number of output channels
* @param in_fmt Input sample format
* @param in_channels Number of input channels
* @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore.
* @param flags See AV_CPU_FLAG_xx
* @return NULL on error
*/
AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels,
enum AVSampleFormat in_fmt, int in_channels,
const float *matrix, int flags);
/**
* Free audio sample format converter context
*/
void av_audio_convert_free(AVAudioConvert *ctx);
/**
* Convert between audio sample formats
* @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel.
* @param[in] out_stride distance between consecutive output samples (measured in bytes)
* @param[in] in array of input buffers for each channel
* @param[in] in_stride distance between consecutive input samples (measured in bytes)
* @param len length of audio frame size (measured in samples)
*/
int av_audio_convert(AVAudioConvert *ctx,
void * const out[6], const int out_stride[6],
const void * const in[6], const int in_stride[6], int len);
#endif /* AVCODEC_AUDIOCONVERT_H */

View File

@ -1,156 +0,0 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_SAMPLEFMT_H
#define AVUTIL_SAMPLEFMT_H
#include "libavutil/avutil.h"
/**
* all in native-endian format
*/
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
/**
* Return the name of sample_fmt, or NULL if sample_fmt is not
* recognized.
*/
const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt);
/**
* Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE
* on error.
*/
enum AVSampleFormat av_get_sample_fmt(const char *name);
/**
* Return the planar<->packed alternative form of the given sample format, or
* AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the
* requested planar/packed format, the format returned is the same as the
* input.
*/
enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar);
/**
* Generate a string corresponding to the sample format with
* sample_fmt, or a header if sample_fmt is negative.
*
* @param buf the buffer where to write the string
* @param buf_size the size of buf
* @param sample_fmt the number of the sample format to print the
* corresponding info string, or a negative value to print the
* corresponding header.
* @return the pointer to the filled buffer or NULL if sample_fmt is
* unknown or in case of other errors
*/
char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt);
#if FF_API_GET_BITS_PER_SAMPLE_FMT
/**
* @deprecated Use av_get_bytes_per_sample() instead.
*/
attribute_deprecated
int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt);
#endif
/**
* Return number of bytes per sample.
*
* @param sample_fmt the sample format
* @return number of bytes per sample or zero if unknown for the given
* sample format
*/
int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt);
/**
* Check if the sample format is planar.
*
* @param sample_fmt the sample format to inspect
* @return 1 if the sample format is planar, 0 if it is interleaved
*/
int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt);
/**
* Get the required buffer size for the given audio parameters.
*
* @param[out] linesize calculated linesize, may be NULL
* @param nb_channels the number of channels
* @param nb_samples the number of samples in a single channel
* @param sample_fmt the sample format
* @return required buffer size, or negative error code on failure
*/
int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
enum AVSampleFormat sample_fmt, int align);
/**
* Fill channel data pointers and linesize for samples with sample
* format sample_fmt.
*
* The pointers array is filled with the pointers to the samples data:
* for planar, set the start point of each channel's data within the buffer,
* for packed, set the start point of the entire buffer only.
*
* The linesize array is filled with the aligned size of each channel's data
* buffer for planar layout, or the aligned size of the buffer for all channels
* for packed layout.
*
* @param[out] audio_data array to be filled with the pointer for each channel
* @param[out] linesize calculated linesize
* @param buf the pointer to a buffer containing the samples
* @param nb_channels the number of channels
* @param nb_samples the number of samples in a single channel
* @param sample_fmt the sample format
* @param align buffer size alignment (1 = no alignment required)
* @return 0 on success or a negative error code on failure
*/
int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, uint8_t *buf,
int nb_channels, int nb_samples,
enum AVSampleFormat sample_fmt, int align);
/**
* Allocate a samples buffer for nb_samples samples, and fill data pointers and
* linesize accordingly.
* The allocated samples buffer can be freed by using av_freep(&audio_data[0])
*
* @param[out] audio_data array to be filled with the pointer for each channel
* @param[out] linesize aligned size for audio buffer(s)
* @param nb_channels number of audio channels
* @param nb_samples number of samples per channel
* @param align buffer size alignment (1 = no alignment required)
* @return 0 on success or a negative error code on failure
* @see av_samples_fill_arrays()
*/
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
int nb_samples, enum AVSampleFormat sample_fmt, int align);
#endif /* AVUTIL_SAMPLEFMT_H */

View File

@ -1,303 +0,0 @@
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <chromaprint.h>
#ifdef HAVE_AV_AUDIO_CONVERT
#include "ffmpeg/audioconvert.h"
#include "ffmpeg/samplefmt.h"
#endif
#ifdef _WIN32
#include <windows.h>
#endif
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define BUFFER_SIZE (AVCODEC_MAX_AUDIO_FRAME_SIZE * 2)
int decode_audio_file(ChromaprintContext *chromaprint_ctx, int16_t *buffer1, int16_t *buffer2, const char *file_name, int max_length, int *duration)
{
int i, ok = 0, remaining, length, consumed, buffer_size, codec_ctx_opened = 0;
AVFormatContext *format_ctx = NULL;
AVCodecContext *codec_ctx = NULL;
AVCodec *codec = NULL;
AVStream *stream = NULL;
AVPacket packet, packet_temp;
#ifdef HAVE_AV_AUDIO_CONVERT
AVAudioConvert *convert_ctx = NULL;
#endif
int16_t *buffer;
if (av_open_input_file(&format_ctx, file_name, NULL, 0, NULL) != 0) {
fprintf(stderr, "ERROR: couldn't open the file\n");
goto done;
}
if (av_find_stream_info(format_ctx) < 0) {
fprintf(stderr, "ERROR: couldn't find stream information in the file\n");
goto done;
}
for (i = 0; i < format_ctx->nb_streams; i++) {
codec_ctx = format_ctx->streams[i]->codec;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 64, 0)
if (codec_ctx && codec_ctx->codec_type == CODEC_TYPE_AUDIO) {
#else
if (codec_ctx && codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
#endif
stream = format_ctx->streams[i];
break;
}
}
if (!stream) {
fprintf(stderr, "ERROR: couldn't find any audio stream in the file\n");
goto done;
}
codec = avcodec_find_decoder(codec_ctx->codec_id);
if (!codec) {
fprintf(stderr, "ERROR: unknown codec\n");
goto done;
}
if (avcodec_open(codec_ctx, codec) < 0) {
fprintf(stderr, "ERROR: couldn't open the codec\n");
goto done;
}
codec_ctx_opened = 1;
if (codec_ctx->channels <= 0) {
fprintf(stderr, "ERROR: no channels found in the audio stream\n");
goto done;
}
if (codec_ctx->sample_fmt != SAMPLE_FMT_S16) {
#ifdef HAVE_AV_AUDIO_CONVERT
convert_ctx = av_audio_convert_alloc(SAMPLE_FMT_S16, codec_ctx->channels,
codec_ctx->sample_fmt, codec_ctx->channels, NULL, 0);
if (!convert_ctx) {
fprintf(stderr, "ERROR: couldn't create sample format converter\n");
goto done;
}
#else
fprintf(stderr, "ERROR: unsupported sample format\n");
goto done;
#endif
}
*duration = stream->time_base.num * stream->duration / stream->time_base.den;
av_init_packet(&packet);
av_init_packet(&packet_temp);
remaining = max_length * codec_ctx->channels * codec_ctx->sample_rate;
chromaprint_start(chromaprint_ctx, codec_ctx->sample_rate, codec_ctx->channels);
while (1) {
if (av_read_frame(format_ctx, &packet) < 0) {
break;
}
packet_temp.data = packet.data;
packet_temp.size = packet.size;
while (packet_temp.size > 0) {
buffer_size = BUFFER_SIZE;
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(52, 25, 0)
consumed = avcodec_decode_audio2(codec_ctx,
buffer1, &buffer_size, packet_temp.data, packet_temp.size);
#else
consumed = avcodec_decode_audio3(codec_ctx,
buffer1, &buffer_size, &packet_temp);
#endif
if (consumed < 0) {
break;
}
packet_temp.data += consumed;
packet_temp.size -= consumed;
if (buffer_size <= 0) {
if (buffer_size < 0) {
fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too small\n");
}
continue;
}
if (buffer_size > BUFFER_SIZE) {
fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too large\n");
continue;
}
#ifdef HAVE_AV_AUDIO_CONVERT
if (convert_ctx) {
const void *ibuf[6] = { buffer1 };
void *obuf[6] = { buffer2 };
int istride[6] = { av_get_bits_per_sample_format(codec_ctx->sample_fmt) / 8 };
int ostride[6] = { 2 };
int len = buffer_size / istride[0];
if (av_audio_convert(convert_ctx, obuf, ostride, ibuf, istride, len) < 0) {
break;
}
buffer = buffer2;
buffer_size = len * ostride[0];
}
else {
buffer = buffer1;
}
#else
buffer = buffer1;
#endif
length = MIN(remaining, buffer_size / 2);
if (!chromaprint_feed(chromaprint_ctx, buffer, length)) {
fprintf(stderr, "ERROR: fingerprint calculation failed\n");
goto done;
}
if (max_length) {
remaining -= length;
if (remaining <= 0) {
goto finish;
}
}
}
if (packet.data) {
av_free_packet(&packet);
}
}
finish:
if (!chromaprint_finish(chromaprint_ctx)) {
fprintf(stderr, "ERROR: fingerprint calculation failed\n");
goto done;
}
ok = 1;
done:
if (codec_ctx_opened) {
avcodec_close(codec_ctx);
}
if (format_ctx) {
av_close_input_file(format_ctx);
}
#ifdef HAVE_AV_AUDIO_CONVERT
if (convert_ctx) {
av_audio_convert_free(convert_ctx);
}
#endif
return ok;
}
int fpcalc_main(int argc, char **argv)
{
int i, j, max_length = 120, num_file_names = 0, raw = 0, raw_fingerprint_size, duration;
int16_t *buffer1, *buffer2;
int32_t *raw_fingerprint;
char *file_name, *fingerprint, **file_names;
ChromaprintContext *chromaprint_ctx;
file_names = malloc(argc * sizeof(char *));
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (!strcmp(arg, "-length") && i + 1 < argc) {
max_length = atoi(argv[++i]);
}
else if (!strcmp(arg, "-raw")) {
raw = 1;
}
else {
file_names[num_file_names++] = argv[i];
}
}
if (!num_file_names) {
printf("usage: %s [OPTIONS] FILE...\n\n", argv[0]);
printf("Options:\n");
printf(" -length SECS length of the audio data used for fingerprint calculation (default 120)\n");
printf(" -raw output the raw uncompressed fingerprint\n");
return 2;
}
av_register_all();
av_log_set_level(AV_LOG_ERROR);
buffer1 = av_malloc(BUFFER_SIZE + 16);
buffer2 = av_malloc(BUFFER_SIZE + 16);
chromaprint_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
for (i = 0; i < num_file_names; i++) {
file_name = file_names[i];
if (!decode_audio_file(chromaprint_ctx, buffer1, buffer2, file_name, max_length, &duration)) {
fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name);
continue;
}
if (i > 0) {
printf("\n");
}
printf("FILE=%s\n", file_name);
printf("DURATION=%d\n", duration);
if (raw) {
if (!chromaprint_get_raw_fingerprint(chromaprint_ctx, (void **)&raw_fingerprint, &raw_fingerprint_size)) {
fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name);
continue;
}
printf("FINGERPRINT=");
for (j = 0; j < raw_fingerprint_size; j++) {
printf("%d%s", raw_fingerprint[j], j + 1 < raw_fingerprint_size ? "," : "\n");
}
chromaprint_dealloc(raw_fingerprint);
}
else {
if (!chromaprint_get_fingerprint(chromaprint_ctx, &fingerprint)) {
fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name);
continue;
}
printf("FINGERPRINT=%s\n", fingerprint);
chromaprint_dealloc(fingerprint);
}
}
chromaprint_free(chromaprint_ctx);
av_free(buffer1);
av_free(buffer2);
free(file_names);
return 0;
}
#ifdef _WIN32
int main(int win32_argc, char **win32_argv)
{
int i, argc = 0, buffsize = 0, offset = 0;
char **utf8_argv, *utf8_argv_ptr;
wchar_t **argv;
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
buffsize = 0;
for (i = 0; i < argc; i++) {
buffsize += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL);
}
utf8_argv = av_mallocz(sizeof(char *) * (argc + 1) + buffsize);
utf8_argv_ptr = (char *)utf8_argv + sizeof(char *) * (argc + 1);
for (i = 0; i < argc; i++) {
utf8_argv[i] = &utf8_argv_ptr[offset];
offset += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, &utf8_argv_ptr[offset], buffsize - offset, NULL, NULL);
}
LocalFree(argv);
return fpcalc_main(argc, utf8_argv);
}
#else
int main(int argc, char **argv)
{
return fpcalc_main(argc, argv);
}
#endif

View File

@ -1,12 +0,0 @@
prefix=${CMAKE_INSTALL_PREFIX}
exec_prefix=${EXEC_INSTALL_PREFIX}
libdir=${LIB_INSTALL_DIR}
includedir=${INCLUDE_INSTALL_DIR}
Name: ${PROJECT_NAME}
Description: Audio fingerprint library
URL: http://wiki.acoustid.org/wiki/Chromaprint
Version: ${PROJECT_VERSION}
Libs: -L${LIB_INSTALL_DIR} -lchromaprint
Cflags: -I${INCLUDE_INSTALL_DIR}

View File

@ -1,41 +0,0 @@
include_directories(
${GTEST_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../src
)
set(tests_SOURCES
main.cpp
test_api.cpp
test_combined_buffer.cpp
test_utils.cpp
test_quantizer.cpp
test_filter_utils.cpp
test_integral_image.cpp
test_lloyds.cpp
test_audio_processor.cpp
test_bit_string_reader.cpp
test_bit_string_writer.cpp
test_chromaprint.cpp
test_chroma.cpp
test_chroma_filter.cpp
test_chroma_resampler.cpp
test_fingerprint_compressor.cpp
test_fingerprint_decompressor.cpp
test_fingerprint_calculator.cpp
test_filter.cpp
test_silence_remover.cpp
test_base64.cpp
)
add_executable(all_tests ${tests_SOURCES})
target_link_libraries(all_tests
${GTEST_BOTH_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
chromaprint_p
)
add_custom_target(check
./all_tests $ENV{GTEST_FLAGS}
DEPENDS all_tests
)

View File

@ -1,21 +0,0 @@
#include <algorithm>
#include <vector>
#include "audio_consumer.h"
class AudioBuffer : public Chromaprint::AudioConsumer
{
public:
void Consume(short *input, int length)
{
//cout << "AudioBuffer::Consume(" << length << ")\n";
int last_size = m_data.size();
//cout << "got " << input[0] << " at index " << last_size << "\n";
m_data.resize(last_size + length);
std::copy(input, input + length, m_data.begin() + last_size);
}
const std::vector<short> &data() { return m_data; }
private:
std::vector<short> m_data;
};

View File

@ -1,8 +0,0 @@
#include <gtest/gtest.h>
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,99 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "chromaprint.h"
using namespace std;
TEST(API, Test2SilenceFp)
{
short zeroes[1024];
fill(zeroes, zeroes + 1024, 0);
ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2);
chromaprint_start(ctx, 44100, 1);
for (int i = 0; i < 130; i++) {
chromaprint_feed(ctx, zeroes, 1024);
}
char *fp;
chromaprint_finish(ctx);
chromaprint_get_fingerprint(ctx, &fp);
ASSERT_EQ(18, strlen(fp));
EXPECT_EQ(string("AQAAA0mUaEkSRZEGAA"), string(fp));
}
TEST(API, Test2SilenceRawFp)
{
short zeroes[1024];
fill(zeroes, zeroes + 1024, 0);
ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2);
chromaprint_start(ctx, 44100, 1);
for (int i = 0; i < 130; i++) {
chromaprint_feed(ctx, zeroes, 1024);
}
int32_t *fp;
int length;
chromaprint_finish(ctx);
chromaprint_get_raw_fingerprint(ctx, (void **)&fp, &length);
ASSERT_EQ(3, length);
EXPECT_EQ(627964279, fp[0]);
EXPECT_EQ(627964279, fp[1]);
EXPECT_EQ(627964279, fp[2]);
}
TEST(API, TestEncodeFingerprint)
{
int32_t fingerprint[] = { 1, 0 };
char expected[] = { 55, 0, 0, 2, 65, 0 };
char *encoded;
int encoded_size;
chromaprint_encode_fingerprint(fingerprint, 2, 55, (void **)&encoded, &encoded_size, 0);
ASSERT_EQ(6, encoded_size);
for (int i = 0; i < encoded_size; i++) {
ASSERT_EQ(expected[i], encoded[i]) << "Different at " << i;
}
free(encoded);
}
TEST(API, TestEncodeFingerprintBase64)
{
int32_t fingerprint[] = { 1, 0 };
char expected[] = "NwAAAkEA";
char *encoded;
int encoded_size;
chromaprint_encode_fingerprint(fingerprint, 2, 55, (void **)&encoded, &encoded_size, 1);
ASSERT_EQ(8, encoded_size);
ASSERT_STREQ(expected, encoded);
free(encoded);
}
TEST(API, TestDecodeFingerprint)
{
char data[] = { 55, 0, 0, 2, 65, 0 };
int32_t *fingerprint;
int size;
int algorithm;
chromaprint_decode_fingerprint(data, 6, (void **)&fingerprint, &size, &algorithm, 0);
ASSERT_EQ(2, size);
ASSERT_EQ(55, algorithm);
ASSERT_EQ(1, fingerprint[0]);
ASSERT_EQ(0, fingerprint[1]);
}

View File

@ -1,114 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "test_utils.h"
#include "audio_processor.h"
#include "audio_buffer.h"
#include "utils.h"
using namespace std;
using namespace Chromaprint;
TEST(AudioProcessor, Accessors)
{
vector<short> data = LoadAudioFile("data/test_mono_44100.raw");
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<AudioBuffer> buffer2(new AudioBuffer());
boost::scoped_ptr<AudioProcessor> processor(new AudioProcessor(44100, buffer.get()));
EXPECT_EQ(44100, processor->target_sample_rate());
EXPECT_EQ(buffer.get(), processor->consumer());
processor->set_target_sample_rate(11025);
EXPECT_EQ(11025, processor->target_sample_rate());
processor->set_consumer(buffer2.get());
EXPECT_EQ(buffer2.get(), processor->consumer());
}
TEST(AudioProcessor, PassThrough)
{
vector<short> data = LoadAudioFile("data/test_mono_44100.raw");
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<AudioProcessor> processor(new AudioProcessor(44100, buffer.get()));
processor->Reset(44100, 1);
processor->Consume(&data[0], data.size());
processor->Flush();
ASSERT_EQ(data.size(), buffer->data().size());
for (size_t i = 0; i < data.size(); i++) {
ASSERT_EQ(data[i], buffer->data()[i]) << "Signals differ at index " << i;
}
}
TEST(AudioProcessor, StereoToMono)
{
vector<short> data1 = LoadAudioFile("data/test_stereo_44100.raw");
vector<short> data2 = LoadAudioFile("data/test_mono_44100.raw");
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<AudioProcessor> processor(new AudioProcessor(44100, buffer.get()));
processor->Reset(44100, 2);
processor->Consume(&data1[0], data1.size());
processor->Flush();
ASSERT_EQ(data2.size(), buffer->data().size());
for (size_t i = 0; i < data2.size(); i++) {
ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i;
}
}
TEST(AudioProcessor, ResampleMono)
{
vector<short> data1 = LoadAudioFile("data/test_mono_44100.raw");
vector<short> data2 = LoadAudioFile("data/test_mono_11025.raw");
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<AudioProcessor> processor(new AudioProcessor(11025, buffer.get()));
processor->Reset(44100, 1);
processor->Consume(&data1[0], data1.size());
processor->Flush();
ASSERT_EQ(data2.size(), buffer->data().size());
for (size_t i = 0; i < data2.size(); i++) {
ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i;
}
}
TEST(AudioProcessor, ResampleMonoNonInteger)
{
vector<short> data1 = LoadAudioFile("data/test_mono_44100.raw");
vector<short> data2 = LoadAudioFile("data/test_mono_8000.raw");
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<AudioProcessor> processor(new AudioProcessor(8000, buffer.get()));
processor->Reset(44100, 1);
processor->Consume(&data1[0], data1.size());
processor->Flush();
ASSERT_EQ(data2.size(), buffer->data().size());
for (size_t i = 0; i < data2.size(); i++) {
ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i;
}
}
TEST(AudioProcessor, StereoToMonoAndResample)
{
vector<short> data1 = LoadAudioFile("data/test_stereo_44100.raw");
vector<short> data2 = LoadAudioFile("data/test_mono_11025.raw");
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<AudioProcessor> processor(new AudioProcessor(11025, buffer.get()));
processor->Reset(44100, 2);
processor->Consume(&data1[0], data1.size());
processor->Flush();
ASSERT_EQ(data2.size(), buffer->data().size());
for (size_t i = 0; i < data2.size(); i++) {
ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i;
}
}

View File

@ -1,56 +0,0 @@
#include <gtest/gtest.h>
#include "base64.h"
#include "test_utils.h"
using namespace std;
using namespace Chromaprint;
TEST(Base64, Base64Encode)
{
ASSERT_EQ("eA", Base64Encode("x"));
ASSERT_EQ("eHg", Base64Encode("xx"));
ASSERT_EQ("eHh4", Base64Encode("xxx"));
ASSERT_EQ("eHh4eA", Base64Encode("xxxx"));
ASSERT_EQ("eHh4eHg", Base64Encode("xxxxx"));
ASSERT_EQ("eHh4eHh4", Base64Encode("xxxxxx"));
ASSERT_EQ("_-4", Base64Encode("\xff\xee"));
}
TEST(Base64, Base64Decode)
{
ASSERT_EQ("x", Base64Decode("eA"));
ASSERT_EQ("xx", Base64Decode("eHg"));
ASSERT_EQ("xxx", Base64Decode("eHh4"));
ASSERT_EQ("xxxx", Base64Decode("eHh4eA"));
ASSERT_EQ("xxxxx", Base64Decode("eHh4eHg"));
ASSERT_EQ("xxxxxx", Base64Decode("eHh4eHh4"));
ASSERT_EQ("\xff\xee", Base64Decode("_-4"));
}
TEST(Base64, Base64EncodeLong)
{
char original[] = {
1, 0, 1, 207, 17, 181, 36, 18, 19, 37, 65, 15, 31, 197, 149, 161, 63, 33, 22,
60, 141, 27, 202, 35, 184, 47, 254, 227, 135, 135, 11, 58, 139, 208, 65, 127,
52, 167, 241, 31, 99, 182, 25, 159, 96, 70, 71, 160, 251, 168, 75, 132, 185,
112, 230, 193, 133, 252, 42, 126, 66, 91, 121, 60, 135, 79, 24, 185, 210, 28,
199, 133, 255, 240, 113, 101, 67, 199, 23, 225, 181, 160, 121, 140, 67, 123,
161, 229, 184, 137, 30, 205, 135, 119, 70, 94, 252, 71, 120, 150
};
char encoded[] = "AQABzxG1JBITJUEPH8WVoT8hFjyNG8ojuC_-44eHCzqL0EF_NKfxH2O2GZ9gRkeg-6hLhLlw5sGF_Cp-Qlt5PIdPGLnSHMeF__BxZUPHF-G1oHmMQ3uh5biJHs2Hd0Ze_Ed4lg";
ASSERT_EQ(encoded, Base64Encode(string(original, NELEMS(original))));
}
TEST(Base64, Base64DecodeLong)
{
char original[] = {
1, 0, 1, 207, 17, 181, 36, 18, 19, 37, 65, 15, 31, 197, 149, 161, 63, 33, 22,
60, 141, 27, 202, 35, 184, 47, 254, 227, 135, 135, 11, 58, 139, 208, 65, 127,
52, 167, 241, 31, 99, 182, 25, 159, 96, 70, 71, 160, 251, 168, 75, 132, 185,
112, 230, 193, 133, 252, 42, 126, 66, 91, 121, 60, 135, 79, 24, 185, 210, 28,
199, 133, 255, 240, 113, 101, 67, 199, 23, 225, 181, 160, 121, 140, 67, 123,
161, 229, 184, 137, 30, 205, 135, 119, 70, 94, 252, 71, 120, 150
};
char encoded[] = "AQABzxG1JBITJUEPH8WVoT8hFjyNG8ojuC_-44eHCzqL0EF_NKfxH2O2GZ9gRkeg-6hLhLlw5sGF_Cp-Qlt5PIdPGLnSHMeF__BxZUPHF-G1oHmMQ3uh5biJHs2Hd0Ze_Ed4lg";
ASSERT_EQ(string(original, NELEMS(original)), Base64Decode(string(encoded)));
}

View File

@ -1,47 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "image.h"
#include "classifier.h"
#include "bit_string_reader.h"
#include "utils.h"
#include "test_utils.h"
using namespace std;
using namespace Chromaprint;
TEST(BitStringReader, OneByte)
{
char data[] = { -28 };
BitStringReader reader(string(data, 1));
ASSERT_EQ(0, reader.Read(2));
ASSERT_EQ(1, reader.Read(2));
ASSERT_EQ(2, reader.Read(2));
ASSERT_EQ(3, reader.Read(2));
}
TEST(BitStringReader, TwoBytesIncomplete)
{
char data[] = { -28, 1 };
BitStringReader reader(string(data, 2));
ASSERT_EQ(0, reader.Read(2));
ASSERT_EQ(1, reader.Read(2));
ASSERT_EQ(2, reader.Read(2));
ASSERT_EQ(3, reader.Read(2));
ASSERT_EQ(1, reader.Read(2));
}
TEST(BitStringReader, TwoBytesSplit)
{
char data[] = { -120, 6 };
BitStringReader reader(string(data, 2));
ASSERT_EQ(0, reader.Read(3));
ASSERT_EQ(1, reader.Read(3));
ASSERT_EQ(2, reader.Read(3));
ASSERT_EQ(3, reader.Read(3));
}

View File

@ -1,53 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "image.h"
#include "classifier.h"
#include "bit_string_writer.h"
#include "utils.h"
#include "test_utils.h"
using namespace std;
using namespace Chromaprint;
TEST(BitStringWriter, OneByte)
{
BitStringWriter writer;
writer.Write(0, 2);
writer.Write(1, 2);
writer.Write(2, 2);
writer.Write(3, 2);
writer.Flush();
char expected[] = { -28 };
CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0]));
}
TEST(BitStringWriter, TwoBytesIncomplete)
{
BitStringWriter writer;
writer.Write(0, 2);
writer.Write(1, 2);
writer.Write(2, 2);
writer.Write(3, 2);
writer.Write(1, 2);
writer.Flush();
char expected[] = { -28, 1 };
CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0]));
}
TEST(BitStringWriter, TwoBytesSplit)
{
BitStringWriter writer;
writer.Write(0, 3);
writer.Write(1, 3);
writer.Write(2, 3);
writer.Write(3, 3);
writer.Flush();
char expected[] = { -120, 6 };
CheckString(writer.value(), expected, sizeof(expected)/sizeof(expected[0]));
}

View File

@ -1,125 +0,0 @@
#include <vector>
#include <algorithm>
#include <gtest/gtest.h>
#include "fft_frame.h"
#include "chroma.h"
using namespace std;
using namespace Chromaprint;
class FeatureVectorBuffer : public FeatureVectorConsumer
{
public:
void Consume(std::vector<double> &features)
{
m_features = features;
}
std::vector<double> m_features;
};
TEST(Chroma, NormalA) {
FeatureVectorBuffer buffer;
Chroma chroma(10, 510, 256, 1000, &buffer);
FFTFrame frame(128);
std::fill(frame.data(), frame.data() + frame.size(), 0.0);
frame.data()[113] = 1.0;
chroma.Consume(frame);
ASSERT_EQ(12, buffer.m_features.size());
double expected_features[12] = {
1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
};
for (int i = 0; i < 12; i++) {
EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i;
}
}
TEST(Chroma, NormalGSharp) {
FeatureVectorBuffer buffer;
Chroma chroma(10, 510, 256, 1000, &buffer);
FFTFrame frame(128);
std::fill(frame.data(), frame.data() + frame.size(), 0.0);
frame.data()[112] = 1.0;
chroma.Consume(frame);
ASSERT_EQ(12, buffer.m_features.size());
double expected_features[12] = {
0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
};
for (int i = 0; i < 12; i++) {
EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i;
}
}
TEST(Chroma, NormalB) {
FeatureVectorBuffer buffer;
Chroma chroma(10, 510, 256, 1000, &buffer);
FFTFrame frame(128);
std::fill(frame.data(), frame.data() + frame.size(), 0.0);
frame.data()[64] = 1.0; // 250 Hz
chroma.Consume(frame);
ASSERT_EQ(12, buffer.m_features.size());
double expected_features[12] = {
0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
};
for (int i = 0; i < 12; i++) {
EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i;
}
}
TEST(Chroma, InterpolatedB) {
FeatureVectorBuffer buffer;
Chroma chroma(10, 510, 256, 1000, &buffer);
chroma.set_interpolate(true);
FFTFrame frame(128);
std::fill(frame.data(), frame.data() + frame.size(), 0.0);
frame.data()[64] = 1.0;
chroma.Consume(frame);
ASSERT_EQ(12, buffer.m_features.size());
double expected_features[12] = {
0.0, 0.286905, 0.713095, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
};
for (int i = 0; i < 12; i++) {
EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i;
}
}
TEST(Chroma, InterpolatedA) {
FeatureVectorBuffer buffer;
Chroma chroma(10, 510, 256, 1000, &buffer);
chroma.set_interpolate(true);
FFTFrame frame(128);
std::fill(frame.data(), frame.data() + frame.size(), 0.0);
frame.data()[113] = 1.0;
chroma.Consume(frame);
ASSERT_EQ(12, buffer.m_features.size());
double expected_features[12] = {
0.555242, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.444758,
};
for (int i = 0; i < 12; i++) {
EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i;
}
}
TEST(Chroma, InterpolatedGSharp) {
FeatureVectorBuffer buffer;
Chroma chroma(10, 510, 256, 1000, &buffer);
chroma.set_interpolate(true);
FFTFrame frame(128);
std::fill(frame.data(), frame.data() + frame.size(), 0.0);
frame.data()[112] = 1.0;
chroma.Consume(frame);
ASSERT_EQ(12, buffer.m_features.size());
double expected_features[12] = {
0.401354, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.598646,
};
for (int i = 0; i < 12; i++) {
EXPECT_NEAR(expected_features[i], buffer.m_features[i], 0.0001) << "Different value at index " << i;
}
}

View File

@ -1,74 +0,0 @@
#include <gtest/gtest.h>
#include "image.h"
#include "image_builder.h"
#include "chroma_filter.h"
using namespace std;
using namespace Chromaprint;
TEST(ChromaFilter, Blur2) {
double coefficients[] = { 0.5, 0.5 };
Image image(12);
ImageBuilder builder(&image);
ChromaFilter filter(coefficients, 2, &builder);
double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
std::vector<double> v1(d1, d1 + 12);
std::vector<double> v2(d2, d2 + 12);
std::vector<double> v3(d3, d3 + 12);
filter.Consume(v1);
filter.Consume(v2);
filter.Consume(v3);
ASSERT_EQ(2, image.NumRows());
EXPECT_EQ(0.5, image[0][0]);
EXPECT_EQ(1.5, image[1][0]);
EXPECT_EQ(5.5, image[0][1]);
EXPECT_EQ(6.5, image[1][1]);
}
TEST(ChromaFilter, Blur3) {
double coefficients[] = { 0.5, 0.7, 0.5 };
Image image(12);
ImageBuilder builder(&image);
ChromaFilter filter(coefficients, 3, &builder);
double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d4[] = { 3.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
std::vector<double> v1(d1, d1 + 12);
std::vector<double> v2(d2, d2 + 12);
std::vector<double> v3(d3, d3 + 12);
std::vector<double> v4(d4, d4 + 12);
filter.Consume(v1);
filter.Consume(v2);
filter.Consume(v3);
filter.Consume(v4);
ASSERT_EQ(2, image.NumRows());
EXPECT_FLOAT_EQ(1.7, image[0][0]);
EXPECT_FLOAT_EQ(3.399999999999999, image[1][0]);
EXPECT_FLOAT_EQ(10.199999999999999, image[0][1]);
EXPECT_FLOAT_EQ(11.899999999999999, image[1][1]);
}
TEST(ChromaFilter, Diff) {
double coefficients[] = { 1.0, -1.0 };
Image image(12);
ImageBuilder builder(&image);
ChromaFilter filter(coefficients, 2, &builder);
double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
std::vector<double> v1(d1, d1 + 12);
std::vector<double> v2(d2, d2 + 12);
std::vector<double> v3(d3, d3 + 12);
filter.Consume(v1);
filter.Consume(v2);
filter.Consume(v3);
ASSERT_EQ(2, image.NumRows());
EXPECT_EQ(-1.0, image[0][0]);
EXPECT_EQ(-1.0, image[1][0]);
EXPECT_EQ(-1.0, image[0][1]);
EXPECT_EQ(-1.0, image[1][1]);
}

View File

@ -1,48 +0,0 @@
#include <gtest/gtest.h>
#include "image.h"
#include "image_builder.h"
#include "chroma_resampler.h"
using namespace std;
using namespace Chromaprint;
TEST(ChromaResampler, Test1) {
Image image(12);
ImageBuilder builder(&image);
ChromaResampler resampler(2, &builder);
double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
std::vector<double> v1(d1, d1 + 12);
std::vector<double> v2(d2, d2 + 12);
std::vector<double> v3(d3, d3 + 12);
resampler.Consume(v1);
resampler.Consume(v2);
resampler.Consume(v3);
ASSERT_EQ(1, image.NumRows());
EXPECT_EQ(0.5, image[0][0]);
EXPECT_EQ(5.5, image[0][1]);
}
TEST(ChromaResampler, Test2) {
Image image(12);
ImageBuilder builder(&image);
ChromaResampler resampler(2, &builder);
double d1[] = { 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d2[] = { 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d3[] = { 2.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
double d4[] = { 3.0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
std::vector<double> v1(d1, d1 + 12);
std::vector<double> v2(d2, d2 + 12);
std::vector<double> v3(d3, d3 + 12);
std::vector<double> v4(d4, d4 + 12);
resampler.Consume(v1);
resampler.Consume(v2);
resampler.Consume(v3);
resampler.Consume(v4);
ASSERT_EQ(2, image.NumRows());
EXPECT_EQ(0.5, image[0][0]);
EXPECT_EQ(5.5, image[0][1]);
EXPECT_EQ(2.5, image[1][0]);
EXPECT_EQ(7.5, image[1][1]);
}

View File

@ -1,67 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "audio_processor.h"
#include "test_utils.h"
#include "audio_processor.h"
#include "chroma.h"
#include "chroma_normalizer.h"
#include "chroma_resampler.h"
#include "fft.h"
#include "audio_processor.h"
#include "image.h"
#include "image_builder.h"
#include "utils.h"
using namespace std;
using namespace Chromaprint;
static const int SAMPLE_RATE = 11025;
static const int FRAME_SIZE = 4096;
static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720;
static const int MIN_FREQ = 28;
static const int MAX_FREQ = 3520;
static const int MAX_FILTER_WIDTH = 20;
TEST(Chromaprint, BasicImage)
{
vector<short> data = LoadAudioFile("data/test_stereo_44100.raw");
Chromaprint::Image image(12);
Chromaprint::ImageBuilder image_builder(&image);
Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder);
Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_normalizer);
Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma);
Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft);
processor.Reset(44100, 2);
processor.Consume(&data[0], data.size());
processor.Flush();
double chromagram[][12] = {
{ 0.155444, 0.268618, 0.474445, 0.159887, 0.1761, 0.423511, 0.178933, 0.34433, 0.360958, 0.30421, 0.200217, 0.17072 },
{ 0.159809, 0.238675, 0.286526, 0.166119, 0.225144, 0.449236, 0.162444, 0.371875, 0.259626, 0.483961, 0.24491, 0.17034 },
{ 0.156518, 0.271503, 0.256073, 0.152689, 0.174664, 0.52585, 0.141517, 0.253695, 0.293199, 0.332114, 0.442906, 0.170459 },
{ 0.154183, 0.38592, 0.497451, 0.203884, 0.362608, 0.355691, 0.125349, 0.146766, 0.315143, 0.318133, 0.172547, 0.112769 },
{ 0.201289, 0.42033, 0.509467, 0.259247, 0.322772, 0.325837, 0.140072, 0.177756, 0.320356, 0.228176, 0.148994, 0.132588 },
{ 0.187921, 0.302804, 0.46976, 0.302809, 0.183035, 0.228691, 0.206216, 0.35174, 0.308208, 0.233234, 0.316017, 0.243563 },
{ 0.213539, 0.240346, 0.308664, 0.250704, 0.204879, 0.365022, 0.241966, 0.312579, 0.361886, 0.277293, 0.338944, 0.290351 },
{ 0.227784, 0.252841, 0.295752, 0.265796, 0.227973, 0.451155, 0.219418, 0.272508, 0.376082, 0.312717, 0.285395, 0.165745 },
{ 0.168662, 0.180795, 0.264397, 0.225101, 0.562332, 0.33243, 0.236684, 0.199847, 0.409727, 0.247569, 0.21153, 0.147286 },
{ 0.0491864, 0.0503369, 0.130942, 0.0505802, 0.0694409, 0.0303877, 0.0389852, 0.674067, 0.712933, 0.05762, 0.0245158, 0.0389336 },
{ 0.0814379, 0.0312366, 0.240546, 0.134609, 0.063374, 0.0466124, 0.0752175, 0.657041, 0.680085, 0.0720311, 0.0249404, 0.0673359 },
{ 0.139331, 0.0173442, 0.49035, 0.287237, 0.0453947, 0.0873279, 0.15423, 0.447475, 0.621502, 0.127166, 0.0355933, 0.141163 },
{ 0.115417, 0.0132515, 0.356601, 0.245902, 0.0283943, 0.0588233, 0.117077, 0.499376, 0.715366, 0.100398, 0.0281382, 0.0943482 },
{ 0.047297, 0.0065354, 0.181074, 0.121455, 0.0135504, 0.030693, 0.0613105, 0.631705, 0.73548, 0.0550565, 0.0128093, 0.0460393 },
};
ASSERT_EQ(14, image.NumRows()) << "Numbers of rows doesn't match";
for (int y = 0; y < 14; y++) {
for (int x = 0; x < 12; x++) {
EXPECT_NEAR(chromagram[y][x], image[y][x], 1e-5)
<< "Image not equal at (" << x << ", " << y << ")";
}
}
}

View File

@ -1,95 +0,0 @@
#include <gtest/gtest.h>
#include <algorithm>
#include "combined_buffer.h"
using namespace std;
using namespace Chromaprint;
TEST(CombinedBuffer, Size) {
short buffer1[] = { 1, 2, 3, 4, 5 };
short buffer2[] = { 6, 7, 8 };
CombinedBuffer<short> buffer(buffer1, 5, buffer2, 3);
EXPECT_EQ(8, buffer.Size());
buffer.Shift(1);
EXPECT_EQ(7, buffer.Size());
}
TEST(CombinedBuffer, AccessElements) {
short buffer1[] = { 1, 2, 3, 4, 5 };
short buffer2[] = { 6, 7, 8 };
CombinedBuffer<short> buffer(buffer1, 5, buffer2, 3);
for (int i = 0; i < 8; i++) {
EXPECT_EQ(1 + i, buffer[i]);
}
buffer.Shift(1);
for (int i = 0; i < 7; i++) {
EXPECT_EQ(2 + i, buffer[i]);
}
buffer.Shift(5);
for (int i = 0; i < 2; i++) {
EXPECT_EQ(7 + i, buffer[i]);
}
}
TEST(CombinedBuffer, AccessElementsViaIterator) {
short buffer1[] = { 1, 2, 3, 4, 5 };
short buffer2[] = { 6, 7, 8 };
CombinedBuffer<short> buffer(buffer1, 5, buffer2, 3);
CombinedBuffer<short>::Iterator iter = buffer.Begin();
for (int i = 0; i < 8; i++) {
EXPECT_EQ(1 + i, *iter);
++iter;
}
EXPECT_TRUE(buffer.End() == iter);
}
TEST(CombinedBuffer, AccessElementsViaIteratorAfterShift) {
short buffer1[] = { 1, 2, 3, 4, 5 };
short buffer2[] = { 6, 7, 8 };
CombinedBuffer<short> buffer(buffer1, 5, buffer2, 3);
buffer.Shift(6);
CombinedBuffer<short>::Iterator iter = buffer.Begin();
for (int i = 0; i < 2; i++) {
EXPECT_EQ(7 + i, *iter);
++iter;
}
EXPECT_TRUE(buffer.End() == iter);
}
TEST(CombinedBuffer, CopyUsingStlAlgorithms) {
short buffer1[] = { 1, 2, 3, 4, 5 };
short buffer2[] = { 6, 7, 8 };
short tmp[10];
CombinedBuffer<short> buffer(buffer1, 5, buffer2, 3);
fill(tmp, tmp + 10, 0);
for (int i = 0; i < 10; i++) {
EXPECT_EQ(0, tmp[i]);
}
copy(buffer.Begin(), buffer.End(), tmp);
for (int i = 0; i < 8; i++) {
EXPECT_EQ(1 + i, tmp[i]);
}
for (int i = 8; i < 10; i++) {
EXPECT_EQ(0, tmp[i]);
}
}
TEST(CombinedBuffer, CopyUsingStlAlgorithmsAfterShift) {
short buffer1[] = { 1, 2, 3, 4, 5 };
short buffer2[] = { 6, 7, 8 };
short tmp[10];
CombinedBuffer<short> buffer(buffer1, 5, buffer2, 3);
buffer.Shift(6);
fill(tmp, tmp + 10, 0);
for (int i = 0; i < 10; i++) {
EXPECT_EQ(0, tmp[i]);
}
copy(buffer.Begin(), buffer.End(), tmp);
for (int i = 0; i < 2; i++) {
EXPECT_EQ(7 + i, tmp[i]);
}
for (int i = 2; i < 10; i++) {
EXPECT_EQ(0, tmp[i]);
}
}

View File

@ -1,25 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "image.h"
#include "filter.h"
using namespace std;
using namespace Chromaprint;
TEST(Filter, Filter0)
{
Image image(2, 2);
image[0][0] = 0.0;
image[0][1] = 1.0;
image[1][0] = 2.0;
image[1][1] = 3.0;
Filter flt1(0, 0, 1, 1);
IntegralImage integral_image(&image);
ASSERT_FLOAT_EQ(0.0, flt1.Apply(&integral_image, 0));
ASSERT_FLOAT_EQ(1.0986123, flt1.Apply(&integral_image, 1));
}

View File

@ -1,118 +0,0 @@
#include <gtest/gtest.h>
#include "filter_utils.h"
using namespace std;
using namespace Chromaprint;
TEST(FilterUtils, CompareSubtract) {
double res = Subtract(2.0, 1.0);
EXPECT_FLOAT_EQ(1.0, res);
}
TEST(FilterUtils, CompareSubtractLog) {
double res = SubtractLog(2.0, 1.0);
EXPECT_FLOAT_EQ(0.4054651, res);
}
TEST(FilterUtils, Filter0) {
double data[] = {
1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0,
};
Image image(3, data, data + 9);
IntegralImage integral_image(&image);
double res;
res = Filter0(&integral_image, 0, 0, 1, 1, Subtract);
EXPECT_FLOAT_EQ(1.0, res);
res = Filter0(&integral_image, 0, 0, 2, 2, Subtract);
EXPECT_FLOAT_EQ(12.0, res);
res = Filter0(&integral_image, 0, 0, 3, 3, Subtract);
EXPECT_FLOAT_EQ(45.0, res);
res = Filter0(&integral_image, 1, 1, 2, 2, Subtract);
EXPECT_FLOAT_EQ(28.0, res);
res = Filter0(&integral_image, 2, 2, 1, 1, Subtract);
EXPECT_FLOAT_EQ(9.0, res);
res = Filter0(&integral_image, 0, 0, 3, 1, Subtract);
EXPECT_FLOAT_EQ(12.0, res);
res = Filter0(&integral_image, 0, 0, 1, 3, Subtract);
EXPECT_FLOAT_EQ(6.0, res);
}
TEST(FilterUtils, Filter1) {
double data[] = {
1.0, 2.0, 3.0,
3.0, 4.0, 5.0,
6.0, 7.0, 8.0,
};
Image image(3, data, data + 9);
IntegralImage integral_image(&image);
double res;
res = Filter1(&integral_image, 0, 0, 1, 1, Subtract);
EXPECT_FLOAT_EQ(1.0, res); // 2 - 1
res = Filter1(&integral_image, 0, 0, 2, 2, Subtract);
EXPECT_FLOAT_EQ(2.0, res); // 2+4 - 1+3
res = Filter1(&integral_image, 0, 0, 3, 2, Subtract);
EXPECT_FLOAT_EQ(3.0, res); // 2+4+7 - 1+3+6
}
TEST(FilterUtils, Filter2) {
double data[] = {
1.0, 2.0, 3.0,
3.0, 4.0, 5.0,
6.0, 7.0, 8.0,
};
Image image(3, data, data + 9);
IntegralImage integral_image(&image);
double res;
res = Filter2(&integral_image, 0, 0, 2, 1, Subtract);
EXPECT_FLOAT_EQ(2.0, res); // 3 - 1
res = Filter2(&integral_image, 0, 0, 2, 2, Subtract);
EXPECT_FLOAT_EQ(4.0, res); // 3+4 - 1+2
res = Filter2(&integral_image, 0, 0, 2, 3, Subtract);
EXPECT_FLOAT_EQ(6.0, res); // 3+4+5 - 1+2+3
}
TEST(FilterUtils, Filter3) {
double data[] = {
1.0, 2.1, 3.4,
3.1, 4.1, 5.1,
6.0, 7.1, 8.0,
};
Image image(3, data, data + 9);
IntegralImage integral_image(&image);
double res;
res = Filter3(&integral_image, 0, 0, 2, 2, Subtract);
EXPECT_FLOAT_EQ(0.1, res); // 2.1+3.1 - 1+4.1
res = Filter3(&integral_image, 1, 1, 2, 2, Subtract);
EXPECT_FLOAT_EQ(0.1, res); // 4+8 - 5+7
res = Filter3(&integral_image, 0, 1, 2, 2, Subtract);
EXPECT_FLOAT_EQ(0.3, res); // 2.1+5.1 - 3.4+4.1
}
TEST(FilterUtils, Filter4) {
double data[] = {
1.0, 2.0, 3.0,
3.0, 4.0, 5.0,
6.0, 7.0, 8.0,
};
Image image(3, data, data + 9);
IntegralImage integral_image(&image);
double res;
res = Filter4(&integral_image, 0, 0, 3, 3, Subtract);
EXPECT_FLOAT_EQ(-13.0, res); // 2+4+7 - (1+3+6) - (3+5+8)
}
TEST(FilterUtils, Filter5) {
double data[] = {
1.0, 2.0, 3.0,
3.0, 4.0, 5.0,
6.0, 7.0, 8.0,
};
Image image(3, data, data + 9);
IntegralImage integral_image(&image);
double res;
res = Filter5(&integral_image, 0, 0, 3, 3, Subtract);
EXPECT_FLOAT_EQ(-15.0, res); // 3+4+5 - (1+2+3) - (6+7+8)
}

View File

@ -1,53 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "image.h"
#include "classifier.h"
#include "fingerprint_calculator.h"
#include "utils.h"
using namespace std;
using namespace Chromaprint;
TEST(FingerprintCalculator, CalculateSubfingerprint)
{
Image image(2, 2);
image[0][0] = 0.0;
image[0][1] = 1.0;
image[1][0] = 2.0;
image[1][1] = 3.0;
Classifier classifiers[] = {
Classifier(Filter(0, 0, 1, 1), Quantizer(0.01, 1.01, 1.5)),
};
FingerprintCalculator calculator(classifiers, 1);
IntegralImage integral_image(&image);
EXPECT_EQ(GrayCode(0), calculator.CalculateSubfingerprint(&integral_image, 0));
EXPECT_EQ(GrayCode(2), calculator.CalculateSubfingerprint(&integral_image, 1));
}
TEST(FingerprintCalculator, Calculate)
{
Image image(2, 3);
image[0][0] = 0.0;
image[0][1] = 1.0;
image[1][0] = 2.0;
image[1][1] = 3.0;
image[2][0] = 4.0;
image[2][1] = 5.0;
Classifier classifiers[] = {
Classifier(Filter(0, 0, 1, 1), Quantizer(0.01, 1.01, 1.5)),
};
FingerprintCalculator calculator(classifiers, 1);
vector<int32_t> fp = calculator.Calculate(&image);
ASSERT_EQ(3, fp.size());
EXPECT_EQ(GrayCode(0), fp[0]);
EXPECT_EQ(GrayCode(2), fp[1]);
EXPECT_EQ(GrayCode(3), fp[2]);
}

View File

@ -1,79 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "image.h"
#include "classifier.h"
#include "fingerprint_compressor.h"
#include "utils.h"
#include "test_utils.h"
using namespace std;
using namespace Chromaprint;
TEST(FingerprintCompressor, OneItemOneBit)
{
FingerprintCompressor compressor;
int32_t fingerprint[] = { 1 };
string value = compressor.Compress(vector<int32_t>(fingerprint, fingerprint + 1));
char expected[] = { 0, 0, 0, 1, 1 };
CheckString(value, expected, sizeof(expected)/sizeof(expected[0]));
}
TEST(FingerprintCompressor, OneItemThreeBits)
{
FingerprintCompressor compressor;
int32_t fingerprint[] = { 7 };
string value = compressor.Compress(vector<int32_t>(fingerprint, fingerprint + 1));
char expected[] = { 0, 0, 0, 1, 73, 0 };
CheckString(value, expected, sizeof(expected)/sizeof(expected[0]));
}
TEST(FingerprintCompressor, OneItemOneBitExcept)
{
FingerprintCompressor compressor;
int32_t fingerprint[] = { 1<<6 };
string value = compressor.Compress(vector<int32_t>(fingerprint, fingerprint + 1));
char expected[] = { 0, 0, 0, 1, 7, 0 };
CheckString(value, expected, sizeof(expected)/sizeof(expected[0]));
}
TEST(FingerprintCompressor, OneItemOneBitExcept2)
{
FingerprintCompressor compressor;
int32_t fingerprint[] = { 1<<8 };
string value = compressor.Compress(vector<int32_t>(fingerprint, fingerprint + 1));
char expected[] = { 0, 0, 0, 1, 7, 2 };
CheckString(value, expected, sizeof(expected)/sizeof(expected[0]));
}
TEST(FingerprintCompressor, TwoItems)
{
FingerprintCompressor compressor;
int32_t fingerprint[] = { 1, 0 };
string value = compressor.Compress(vector<int32_t>(fingerprint, fingerprint + 2));
char expected[] = { 0, 0, 0, 2, 65, 0 };
CheckString(value, expected, sizeof(expected)/sizeof(expected[0]));
}
TEST(FingerprintCompressor, TwoItemsNoChange)
{
FingerprintCompressor compressor;
int32_t fingerprint[] = { 1, 1 };
string value = compressor.Compress(vector<int32_t>(fingerprint, fingerprint + 2));
char expected[] = { 0, 0, 0, 2, 1, 0 };
CheckString(value, expected, sizeof(expected)/sizeof(expected[0]));
}

View File

@ -1,77 +0,0 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <vector>
#include "fingerprint_decompressor.h"
#include "utils.h"
#include "test_utils.h"
using namespace std;
using namespace Chromaprint;
TEST(FingerprintDecompressor, OneItemOneBit)
{
int32_t expected[] = { 1 };
char data[] = { 0, 0, 0, 1, 1 };
int algorithm = 1;
vector<int32_t> value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm);
CheckFingerprints(value, expected, NELEMS(expected));
ASSERT_EQ(0, algorithm);
}
TEST(FingerprintDecompressor, OneItemThreeBits)
{
int32_t expected[] = { 7 };
char data[] = { 0, 0, 0, 1, 73, 0 };
int algorithm = 1;
vector<int32_t> value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm);
CheckFingerprints(value, expected, NELEMS(expected));
ASSERT_EQ(0, algorithm);
}
TEST(FingerprintDecompressor, OneItemOneBitExcept)
{
int32_t expected[] = { 1<<6 };
char data[] = { 0, 0, 0, 1, 7, 0 };
int algorithm = 1;
vector<int32_t> value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm);
CheckFingerprints(value, expected, NELEMS(expected));
ASSERT_EQ(0, algorithm);
}
TEST(FingerprintDecompressor, OneItemOneBitExcept2)
{
int32_t expected[] = { 1<<8 };
char data[] = { 0, 0, 0, 1, 7, 2 };
int algorithm = 1;
vector<int32_t> value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm);
CheckFingerprints(value, expected, NELEMS(expected));
ASSERT_EQ(0, algorithm);
}
TEST(FingerprintDecompressor, TwoItems)
{
int32_t expected[] = { 1, 0 };
char data[] = { 0, 0, 0, 2, 65, 0 };
int algorithm = 1;
vector<int32_t> value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm);
CheckFingerprints(value, expected, NELEMS(expected));
ASSERT_EQ(0, algorithm);
}
TEST(FingerprintDecompressor, TwoItemsNoChange)
{
int32_t expected[] = { 1, 1 };
char data[] = { 0, 0, 0, 2, 1, 0 };
int algorithm = 1;
vector<int32_t> value = DecompressFingerprint(string(data, NELEMS(data)), &algorithm);
CheckFingerprints(value, expected, NELEMS(expected));
ASSERT_EQ(0, algorithm);
}

View File

@ -1,40 +0,0 @@
#include <gtest/gtest.h>
#include "integral_image.h"
using namespace std;
using namespace Chromaprint;
TEST(IntegralImage, Basic2D) {
double data[] = {
1.0, 2.0,
3.0, 4.0,
};
Image image(2, data, data + 4);
IntegralImage integral_image(&image);
EXPECT_FLOAT_EQ(1.0, integral_image[0][0]);
EXPECT_FLOAT_EQ(3.0, integral_image[0][1]);
EXPECT_FLOAT_EQ(4.0, integral_image[1][0]);
EXPECT_FLOAT_EQ(10.0, integral_image[1][1]);
}
TEST(IntegralImage, Vertical1D) {
double data[] = {
1.0, 2.0, 3.0
};
Image image(1, data, data + 3);
IntegralImage integral_image(&image);
EXPECT_FLOAT_EQ(1.0, integral_image[0][0]);
EXPECT_FLOAT_EQ(3.0, integral_image[1][0]);
EXPECT_FLOAT_EQ(6.0, integral_image[2][0]);
}
TEST(IntegralImage, Horizontal1D) {
double data[] = {
1.0, 2.0, 3.0
};
Image image(3, data, data + 3);
IntegralImage integral_image(&image);
EXPECT_FLOAT_EQ(1.0, integral_image[0][0]);
EXPECT_FLOAT_EQ(3.0, integral_image[0][1]);
EXPECT_FLOAT_EQ(6.0, integral_image[0][2]);
}

View File

@ -1,80 +0,0 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <limits>
#include "lloyds.h"
using namespace std;
template<class T>
ostream &operator<<(ostream &stream, const vector<T> &vec)
{
for (int i = 0; i < vec.size(); i++) {
if (i != 0)
stream << ", ";
stream << vec[i];
}
return stream;
}
/*TEST(Lloyds, Long) {
double signal[] = {
-2.23622, -2.2133, -2.08922, -2.02973, -2.01912, -2.00194, -1.94793, -1.92903, -1.90671, -1.90311, -1.86394, -1.82542, -1.82281, -1.77955, -1.77286, -1.77119, -1.76317, -1.74447, -1.74447, -1.71927, -1.71244, -1.70758, -1.69632, -1.69448, -1.68845, -1.68842, -1.65839, -1.64934, -1.63575, -1.61216, -1.56943, -1.56546, -1.5601, -1.5584, -1.53875, -1.52408, -1.51576, -1.47345, -1.44838, -1.44712, -1.43751, -1.43722, -1.43159, -1.41818, -1.41585, -1.36654, -1.36556, -1.36486, -1.3596, -1.35941, -1.35301, -1.35301, -1.35145, -1.34479, -1.34443, -1.3441, -1.3381, -1.3334, -1.31715, -1.31105, -1.31071, -1.30166, -1.29944, -1.29715, -1.29669, -1.29634, -1.28696, -1.28504, -1.27143, -1.26548, -1.26533, -1.26421, -1.26054, -1.25978, -1.25631, -1.24751, -1.23887, -1.23797, -1.23588, -1.22391, -1.21961, -1.21559, -1.21499, -1.19502, -1.19009, -1.18784, -1.18746, -1.18264, -1.17917, -1.17597, -1.17482, -1.1664, -1.15644, -1.15584, -1.15317, -1.14694, -1.14341, -1.14246, -1.14234, -1.14027, -1.13955, -1.13745, -1.13674, -1.12764, -1.12735, -1.12729, -1.12645, -1.12578, -1.12533, -1.12131, -1.11019, -1.10879, -1.10357, -1.09973, -1.09187, -1.09187, -1.06664, -1.06356, -1.0554, -1.0492, -1.04506, -1.04027, -1.03942, -1.03896, -1.034, -1.03285, -1.02334, -1.02084, -1.01993, -1.01447, -1.01447, -1.01447, -1.00864, -1.00689, -1.00471, -1.00125, -0.999809, -0.998627, -0.998156, -0.994751, -0.994212, -0.993412, -0.992572, -0.992572, -0.992548, -0.992472, -0.989607, -0.987201, -0.982932, -0.982652, -0.980823, -0.976318, -0.974594, -0.973334, -0.97326, -0.971969, -0.970954, -0.964969, -0.963816, -0.960578, -0.959536, -0.95708, -0.953791, -0.953782, -0.952128, -0.951757, -0.95172, -0.951264, -0.950896, -0.949007, -0.947225, -0.945958, -0.945852, -0.945044, -0.94482, -0.940381, -0.940254, -0.940084, -0.939844, -0.937978, -0.935127, -0.93345, -0.931299, -0.931147, -0.929513, -0.927091, -0.926682, -0.926458, -0.925325, -0.918487, -0.917891, -0.917015, -0.916352, -0.915526, -0.915489, -0.913747, -0.91204, -0.911457, -0.911281, -0.910753, -0.909806, -0.909361, -0.908686, -0.907, -0.906509, -0.903637, -0.902177, -0.896958, -0.896304, -0.895733, -0.889965, -0.886484, -0.884943, -0.882143, -0.879831, -0.879507, -0.876134, -0.875782, -0.873226, -0.873167, -0.872282, -0.870152, -0.869655, -0.869655, -0.866992, -0.862656, -0.862331, -0.861969, -0.861246, -0.856819, -0.854323, -0.853294, -0.846832, -0.843682, -0.842113, -0.840478, -0.835353, -0.83055, -0.828979, -0.828979, -0.828088, -0.826904, -0.826844, -0.826474, -0.820101, -0.819027, -0.819027, -0.818121, -0.812784, -0.812206, -0.810112, -0.806803, -0.805296, -0.80126, -0.800501, -0.798129, -0.797067, -0.786663, -0.785991, -0.784662, -0.78212, -0.776524, -0.774306, -0.772335, -0.771675, -0.771675, -0.77125, -0.770083, -0.769165, -0.767499, -0.766419, -0.763909, -0.762582, -0.76243, -0.761753, -0.761182, -0.759494, -0.755514, -0.745122, -0.742554, -0.739007, -0.73575, -0.735359, -0.73376, -0.732161, -0.728712, -0.726951, -0.726218, -0.725935, -0.724686, -0.722143, -0.722044, -0.721563, -0.721248, -0.720543, -0.719718, -0.716511, -0.714431, -0.714329, -0.712779, -0.712512, -0.712512, -0.711802, -0.71157, -0.709608, -0.706909, -0.706774, -0.704839, -0.703444, -0.702687, -0.70263, -0.702272, -0.700726, -0.700691, -0.700566, -0.698961, -0.697583, -0.697153, -0.696813, -0.696062, -0.695309, -0.694557, -0.691675, -0.691434, -0.687548, -0.686447, -0.684052, -0.68283, -0.682705, -0.682523, -0.682514, -0.679172, -0.675747, -0.675161, -0.673046, -0.670132, -0.663973, -0.659537, -0.655187, -0.65481, -0.653818, -0.65335, -0.653181, -0.649845, -0.649723, -0.648533, -0.647648, -0.645932, -0.645885, -0.645736, -0.643418, -0.642324, -0.642275, -0.641053, -0.641053, -0.636907, -0.635015, -0.634658, -0.632863, -0.629322, -0.629234, -0.628869, -0.627114, -0.626578, -0.626576, -0.62511, -0.625091, -0.621436, -0.620774, -0.616916, -0.616051, -0.612722, -0.611527, -0.610163, -0.609325, -0.606185, -0.606169, -0.606019, -0.603731, -0.602434, -0.596665, -0.596236, -0.595822, -0.594053, -0.588736, -0.588164, -0.586796, -0.586709, -0.585038, -0.583978, -0.583929, -0.582533, -0.576205, -0.57511
};
vector<double> r = lloyds(signal, signal + sizeof(signal) / sizeof(signal[0]), 10);
EXPECT_EQ(9, r.size());
EXPECT_FLOAT_EQ(-2.15126, r[0]);
EXPECT_FLOAT_EQ(-1.95019, r[1]);
EXPECT_FLOAT_EQ(-1.72034, r[2]);
EXPECT_FLOAT_EQ(-1.42570, r[3]);
EXPECT_FLOAT_EQ(-1.23976, r[4]);
EXPECT_FLOAT_EQ(-1.06092, r[5]);
EXPECT_FLOAT_EQ(-0.93395, r[6]);
EXPECT_FLOAT_EQ(-0.81530, r[7]);
EXPECT_FLOAT_EQ(-0.68837, r[8]);
}*/
TEST(LLoyds, Lloyds1) {
double data[] = {
1.0, 1.1, 1.2,
3.0, 3.1, 3.2,
};
vector<double> sig(data, data + 6);
vector<double> table = lloyds(sig, 2);
EXPECT_EQ(1, table.size());
EXPECT_FLOAT_EQ(2.1, table[0]);
}
TEST(LLoyds, Lloyds2) {
double data[] = {
1.0, 1.1, 1.2,
};
vector<double> sig(data, data + 3);
vector<double> table = lloyds(sig, 2);
EXPECT_EQ(1, table.size());
EXPECT_FLOAT_EQ(1.075, table[0]);
}
TEST(LLoyds, Lloyds3) {
double data[] = {
1.0, 1.1, 1.2,
};
vector<double> sig(data, data + 3);
vector<double> table = lloyds(sig, 3);
EXPECT_EQ(2, table.size());
EXPECT_FLOAT_EQ(1.05, table[0]);
EXPECT_FLOAT_EQ(1.15, table[1]);
}
TEST(LLoyds, Lloyds4) {
double data[] = {
435,219,891,906,184,572,301,892,875,121,245,146,640,137,938,25,668,288,848,790,141,890,528,145,289,861,339,769,293,757
};
vector<double> sig(data, data + 30);
vector<double> table = lloyds(sig, 4);
EXPECT_EQ(3, table.size());
EXPECT_FLOAT_EQ(214.77678, table[0]);
EXPECT_FLOAT_EQ(451.5625, table[1]);
EXPECT_FLOAT_EQ(729.04547, table[2]);
}

View File

@ -1,17 +0,0 @@
#include <gtest/gtest.h>
#include "quantizer.h"
using namespace std;
using namespace Chromaprint;
TEST(Quantizer, Quantize) {
Quantizer q(0.0, 0.1, 0.3);
EXPECT_EQ(0, q.Quantize(-0.1));
EXPECT_EQ(1, q.Quantize(0.0));
EXPECT_EQ(1, q.Quantize(0.03));
EXPECT_EQ(2, q.Quantize(0.1));
EXPECT_EQ(2, q.Quantize(0.13));
EXPECT_EQ(3, q.Quantize(0.3));
EXPECT_EQ(3, q.Quantize(0.33));
EXPECT_EQ(3, q.Quantize(1000.0));
}

View File

@ -1,49 +0,0 @@
#include <gtest/gtest.h>
#include <boost/scoped_ptr.hpp>
#include <algorithm>
#include <vector>
#include <fstream>
#include "test_utils.h"
#include "silence_remover.h"
#include "audio_buffer.h"
#include "utils.h"
using namespace std;
using namespace Chromaprint;
TEST(SilenceRemover, PassThrough)
{
short samples[] = { 1, 2, 3, 4, 5, 6 };
vector<short> data(samples, samples + 6);
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<SilenceRemover> processor(new SilenceRemover(buffer.get()));
processor->Reset(44100, 1);
processor->Consume(&data[0], data.size());
processor->Flush();
ASSERT_EQ(data.size(), buffer->data().size());
for (size_t i = 0; i < data.size(); i++) {
ASSERT_EQ(data[i], buffer->data()[i]) << "Signals differ at index " << i;
}
}
TEST(SilenceRemover, RemoveLeadingSilence)
{
short samples1[] = { 0, 0, 1, 2, 0, 4, 5, 0 };
vector<short> data1(samples1, samples1 + 8);
short samples2[] = { 1, 2, 0, 4, 5, 0 };
vector<short> data2(samples2, samples2 + 6);
boost::scoped_ptr<AudioBuffer> buffer(new AudioBuffer());
boost::scoped_ptr<SilenceRemover> processor(new SilenceRemover(buffer.get()));
processor->Reset(44100, 1);
processor->Consume(&data1[0], data1.size());
processor->Flush();
ASSERT_EQ(data2.size(), buffer->data().size());
for (size_t i = 0; i < data2.size(); i++) {
ASSERT_EQ(data2[i], buffer->data()[i]) << "Signals differ at index " << i;
}
}

View File

@ -1,91 +0,0 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <limits>
#include "utils.h"
using namespace std;
using namespace Chromaprint;
TEST(Utils, PrepareHammingWindow) {
double window_ex[10] = { 0.08, 0.187619556165, 0.460121838273, 0.77, 0.972258605562, 0.972258605562, 0.77, 0.460121838273, 0.187619556165, 0.08};
double window[10];
PrepareHammingWindow(window, window + 10);
for (int i = 0; i < 10; i++) {
EXPECT_FLOAT_EQ(window_ex[i], window[i]);
}
}
TEST(Utils, ApplyWindow1) {
double window_ex[10] = { 0.08, 0.187619556165, 0.460121838273, 0.77, 0.972258605562, 0.972258605562, 0.77, 0.460121838273, 0.187619556165, 0.08};
double window[10];
short input[10];
double output[10];
PrepareHammingWindow(window, window + 10);
fill(input, input + 10, numeric_limits<short>::max());
double scale = 1.0 / numeric_limits<short>::max();
ApplyWindow(input, window, output, 10, scale);
for (int i = 0; i < 10; i++) {
EXPECT_FLOAT_EQ(window_ex[i], output[i]);
}
}
TEST(Utils, ApplyWindow2) {
double window[10];
short input[10];
double output[10];
PrepareHammingWindow(window, window + 10);
fill(input, input + 10, 0);
double scale = 1.0 / numeric_limits<short>::max();
ApplyWindow(input, window, output, 10, scale);
for (int i = 0; i < 10; i++) {
EXPECT_FLOAT_EQ(0.0, output[i]);
}
}
TEST(Utils, Sum) {
double data[] = { 0.1, 0.2, 0.4, 1.0 };
EXPECT_FLOAT_EQ(1.7, Sum(data, data + 4));
}
TEST(Utils, EuclideanNorm) {
double data[] = { 0.1, 0.2, 0.4, 1.0 };
EXPECT_FLOAT_EQ(1.1, EuclideanNorm(data, data + 4));
}
TEST(Utils, NormalizeVector) {
double data[] = { 0.1, 0.2, 0.4, 1.0 };
double normalized_data[] = { 0.090909, 0.181818, 0.363636, 0.909091 };
NormalizeVector(data, data + 4, EuclideanNorm<double *>, 0.01);
for (int i = 0; i < 4; i++) {
EXPECT_NEAR(normalized_data[i], data[i], 1e-5) << "Wrong data at index " << i;
}
}
TEST(Utils, NormalizeVectorNearZero) {
double data[] = { 0.0, 0.001, 0.002, 0.003 };
NormalizeVector(data, data + 4, EuclideanNorm<double *>, 0.01);
for (int i = 0; i < 4; i++) {
EXPECT_FLOAT_EQ(0.0, data[i]) << "Wrong data at index " << i;
}
}
TEST(Utils, NormalizeVectorZero) {
double data[] = { 0.0, 0.0, 0.0, 0.0 };
NormalizeVector(data, data + 4, EuclideanNorm<double *>, 0.01);
for (int i = 0; i < 4; i++) {
EXPECT_FLOAT_EQ(0.0, data[i]) << "Wrong data at index " << i;
}
}
TEST(Utils, UnsignedToSigned) {
EXPECT_EQ(numeric_limits<int32_t>::max(), UnsignedToSigned(0x7FFFFFFFU));
EXPECT_EQ(-1, UnsignedToSigned(0xFFFFFFFFU));
EXPECT_EQ(-2, UnsignedToSigned(0xFFFFFFFEU));
EXPECT_EQ(numeric_limits<int32_t>::min(), UnsignedToSigned(0x80000000U));
EXPECT_EQ(numeric_limits<int32_t>::min() + 1, UnsignedToSigned(0x80000001U));
}
TEST(Utils, IsNaN) {
EXPECT_FALSE(IsNaN(0.0));
EXPECT_TRUE(IsNaN(sqrt(-1.0)));
}

View File

@ -1,42 +0,0 @@
#ifndef CHROMAPRINT_TESTS_UTILS_H_
#define CHROMAPRINT_TESTS_UTILS_H_
#include <vector>
#include <fstream>
#include <string>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define NELEMS(x) (sizeof(x)/sizeof(x[0]))
inline void CheckString(std::string actual, char *expected, int expected_size)
{
ASSERT_EQ(expected_size, actual.size());
for (int i = 0; i < expected_size; i++) {
EXPECT_EQ(expected[i], actual[i]) << "Different at index " << i;
}
}
inline void CheckFingerprints(std::vector<int32_t> actual, int32_t *expected, int expected_size)
{
ASSERT_EQ(expected_size, actual.size());
for (int i = 0; i < expected_size; i++) {
EXPECT_EQ(expected[i], actual[i]) << "Different at index " << i;
}
}
inline std::vector<short> LoadAudioFile(const std::string &file_name)
{
std::string path = TESTS_DIR + file_name;
std::ifstream file(path.c_str(), std::ifstream::in);
file.seekg(0, std::ios::end);
int length = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<short> data(length / 2);
file.read((char *)&data[0], length);
file.close();
return data;
}
#endif

View File

@ -1,63 +0,0 @@
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../src
${FFMPEG_LIBAVCODEC_INCLUDE_DIRS}
${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}
${FFMPEG_LIBAVUTIL_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${TAGLIB_INCLUDES}
)
if(BUILD_EXTRA_TOOLS)
add_executable(resample resample.cpp)
target_link_libraries(resample chromaprint_p
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES})
add_executable(decode decode.cpp)
target_link_libraries(decode chromaprint_p
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES})
add_executable(chromagram chromagram.cpp)
target_link_libraries(chromagram chromaprint_p
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES}
-lpng)
add_executable(spectrogram spectrogram.cpp)
target_link_libraries(spectrogram chromaprint_p
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES}
-lpng)
add_executable(learn_filters learn_filters.cpp)
target_link_libraries(learn_filters chromaprint_p
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES}
${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY})
add_executable(fpeval fpeval.cpp)
target_link_libraries(fpeval chromaprint_p
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES}
${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY})
endif(BUILD_EXTRA_TOOLS)
if(NOT MSVC)
add_executable(fpcollect fpcollect.cpp)
target_link_libraries(fpcollect chromaprint_p
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES}
${TAGLIB_LIBRARIES})
endif()

View File

@ -1,65 +0,0 @@
#include <string>
#include <iostream>
using namespace std;
#include "ext/ffmpeg_decoder.h"
#include "ext/audio_dumper.h"
#include "audio_processor.h"
#include "chroma.h"
#include "spectral_centroid.h"
#include "chroma_normalizer.h"
#include "chroma_resampler.h"
#include "chroma_filter.h"
#include "fft.h"
#include "audio_processor.h"
#include "image.h"
#include "image_builder.h"
#include "utils.h"
#include "ext/image_utils.h"
static const int SAMPLE_RATE = 11025;
static const int FRAME_SIZE = 4096;
static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720;
static const int MIN_FREQ = 28;
static const int MAX_FREQ = 3520;
static const int MAX_FILTER_WIDTH = 20;
static const int kChromaFilterSize = 5;
static const double kChromaFilterCoefficients[] = { 0.25, 0.75, 1.0, 0.75, 0.25 };
int main(int argc, char **argv)
{
if (argc < 3) {
cerr << "Usage: " << argv[0] << " AUDIOFILE IMAGEFILE\n";
return 1;
}
string file_name(argv[1]);
cout << "Loading file " << file_name << "\n";
Decoder decoder(file_name);
if (!decoder.Open()) {
cerr << "ERROR: " << decoder.LastError() << "\n";
return 2;
}
Chromaprint::Image image(12);
Chromaprint::ImageBuilder image_builder(&image);
Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder);
Chromaprint::ChromaFilter chroma_filter(kChromaFilterCoefficients, kChromaFilterSize, &chroma_normalizer);
//Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_normalizer);
Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_filter);
Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma);
Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft);
processor.Reset(decoder.SampleRate(), decoder.Channels());
decoder.Decode(&processor);
processor.Flush();
//Chromaprint::ExportTextImage(&image, argv[2]);
Chromaprint::ExportImage(&image, argv[2]);
return 0;
}

View File

@ -1,28 +0,0 @@
#include <string>
#include <iostream>
using namespace std;
#include "ext/ffmpeg_decoder.h"
#include "ext/audio_dumper.h"
int main(int argc, char **argv)
{
if (argc < 3) {
cerr << "Usage: " << argv[0] << " FILENAME\n";
return 1;
}
string file_name(argv[1]);
Decoder decoder(file_name);
if (!decoder.Open()) {
cerr << "ERROR: " << decoder.LastError() << "\n";
return 2;
}
AudioDumper dumper(argv[2]);
decoder.Decode(&dumper);
return 0;
}

View File

@ -1,76 +0,0 @@
#!/usr/bin/env python
import time
import sys
from optparse import OptionParser
import subprocess
import os.path
from xml.etree import ElementTree
usage = "usage: %prog [options] logfile"
parser = OptionParser(usage=usage)
parser.add_option("-a", "--musicdns-apikey", dest="musicdns_api_key", metavar="KEY",
help="MusicDNS API key")
parser.add_option("-g", "--genpuid", dest="genpuid_path", metavar="PATH",
help="path to the GenPUID binary", default="genpuid")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error("no log file specified")
def read_log_file(input):
group = {}
for line in input:
line = line.strip()
if not line:
if group:
yield group
group = {}
continue
name, value = line.split('=', 1)
group[name] = value
if group:
yield group
def make_groups(input, size=10):
group = []
for entry in input:
group.append(entry)
if len(group) >= size:
yield group
group = []
if group:
yield group
def write_log_file(entry):
for row in entry.iteritems():
print '%s=%s' % row
print
def call_genpuid(entries):
paths = [e['FILENAME'] for e in entries]
process = subprocess.Popen([options.genpuid_path, options.musicdns_api_key, '-xml'] + paths, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
tree = ElementTree.fromstring('<?xml version="1.0" encoding="iso-8859-1"?>' + out)
puids = {}
for track in tree.findall("track"):
if 'puid' in track.attrib and 'file' in track.attrib:
puids[os.path.normpath(track.attrib['file']).encode('iso-8859-1')] = track.attrib['puid']
for entry in entries:
path = os.path.normpath(entry['FILENAME'])
if path in puids:
entry['PUID'] = puids[path]
for entries in make_groups(read_log_file(open(args[0]) if args[0] != '-' else sys.stdin), 20):
call_genpuid([e for e in entries if 'MBID' not in e])
for entry in entries:
print >>sys.stderr, entry['FILENAME']
write_log_file(entry)

View File

@ -1,323 +0,0 @@
#include <iostream>
#include <dirent.h>
#include <sys/stat.h>
//#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <fileref.h>
#include <tag.h>
#include "chromaprint.h"
#include "fingerprinter.h"
#include "fingerprinter_configuration.h"
#include "fingerprint_compressor.h"
#include "base64.h"
#include "ext/ffmpeg_decoder.h"
using namespace std;
static const int kChromaprintAlgorithm = CHROMAPRINT_ALGORITHM_DEFAULT;
typedef vector<string> string_vector;
void FindFiles(const string &dirname, string_vector *result, time_t changed_since)
{
DIR *dirp = opendir(dirname.c_str());
if (!dirp) {
if (errno == ENOTDIR) {
result->push_back(dirname);
}
return;
}
while (dirp) {
struct dirent *dp;
if ((dp = readdir(dirp)) != NULL) {
struct stat sp;
string filename = dirname + '/' + string(dp->d_name);
stat(filename.c_str(), &sp);
if (S_ISREG(sp.st_mode)) {
//cerr << "file " << filename << " mtime=" << sp.st_mtime << " ch=" << changed_since << "\n";
if (!changed_since || sp.st_mtime >= changed_since) {
result->push_back(filename);
}
}
if (S_ISDIR(sp.st_mode) && dp->d_name[0] != '.') {
FindFiles(filename, result, changed_since);
}
}
else {
break;
}
}
closedir(dirp);
}
string_vector FindFiles(const string_vector &files, time_t changed_since)
{
string_vector result;
for (size_t i = 0; i < files.size(); i++) {
FindFiles(files[i], &result, changed_since);
}
sort(result.begin(), result.end());
return result;
}
#define DISPATCH_TAGLIB_FILE(type, file) \
{ \
type *tmp = dynamic_cast<type *>(file); \
if (tmp) { \
return ExtractMBIDFromFile(tmp); \
} \
}
#include <xiphcomment.h>
#include <apetag.h>
#include <vorbisfile.h>
#include <oggflacfile.h>
#include <speexfile.h>
#include <flacfile.h>
#include <mpcfile.h>
#include <wavpackfile.h>
#ifdef TAGLIB_WITH_ASF
#include <asffile.h>
#endif
#ifdef TAGLIB_WITH_MP4
#include <mp4file.h>
#endif
#include <mpegfile.h>
#include <id3v2tag.h>
#include <uniquefileidentifierframe.h>
string ExtractMBIDFromXiphComment(TagLib::Ogg::XiphComment *tag)
{
string key = "MUSICBRAINZ_TRACKID";
if (tag && tag->fieldListMap().contains(key)) {
return tag->fieldListMap()[key].front().to8Bit(true);
}
return string();
}
string ExtractMBIDFromAPETag(TagLib::APE::Tag *tag)
{
string key = "MUSICBRAINZ_TRACKID";
if (tag && tag->itemListMap().contains(key)) {
return tag->itemListMap()[key].toString().to8Bit(true);
}
return string();
}
string ExtractMBIDFromFile(TagLib::Ogg::Vorbis::File *file)
{
return ExtractMBIDFromXiphComment(file->tag());
}
string ExtractMBIDFromFile(TagLib::Ogg::FLAC::File *file)
{
return ExtractMBIDFromXiphComment(file->tag());
}
string ExtractMBIDFromFile(TagLib::Ogg::Speex::File *file)
{
return ExtractMBIDFromXiphComment(file->tag());
}
string ExtractMBIDFromFile(TagLib::FLAC::File *file)
{
return ExtractMBIDFromXiphComment(file->xiphComment());
}
string ExtractMBIDFromFile(TagLib::MPC::File *file)
{
return ExtractMBIDFromAPETag(file->APETag());
}
string ExtractMBIDFromFile(TagLib::WavPack::File *file)
{
return ExtractMBIDFromAPETag(file->APETag());
}
/*string ExtractMBIDFromFile(TagLib::APE::File *file)
{
return ExtractMBIDFromAPETag(file->APETag());
}*/
#ifdef TAGLIB_WITH_ASF
string ExtractMBIDFromFile(TagLib::ASF::File *file)
{
string key = "MusicBrainz/Track Id";
TagLib::ASF::Tag *tag = file->tag();
if (tag && tag->attributeListMap().contains(key)) {
return tag->attributeListMap()[key].front().toString().to8Bit(true);
}
return string();
}
#endif
#ifdef TAGLIB_WITH_MP4
string ExtractMBIDFromFile(TagLib::MP4::File *file)
{
string key = "----:com.apple.iTunes:MusicBrainz Track Id";
TagLib::MP4::Tag *tag = file->tag();
if (tag && tag->itemListMap().contains(key)) {
return tag->itemListMap()[key].toStringList().toString().to8Bit(true);
}
return string();
}
#endif
string ExtractMBIDFromFile(TagLib::MPEG::File *file)
{
TagLib::ID3v2::Tag *tag = file->ID3v2Tag();
if (!tag) {
return string();
}
TagLib::ID3v2::FrameList ufid = tag->frameListMap()["UFID"];
if (!ufid.isEmpty()) {
for (TagLib::ID3v2::FrameList::Iterator i = ufid.begin(); i != ufid.end(); i++) {
TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast<TagLib::ID3v2::UniqueFileIdentifierFrame *>(*i);
if (frame && frame->owner() == "http://musicbrainz.org") {
TagLib::ByteVector id = frame->identifier();
return string(id.data(), id.size());
}
}
}
return string();
}
string ExtractMusicBrainzTrackID(TagLib::File *file)
{
DISPATCH_TAGLIB_FILE(TagLib::FLAC::File, file);
DISPATCH_TAGLIB_FILE(TagLib::Ogg::Vorbis::File, file);
DISPATCH_TAGLIB_FILE(TagLib::Ogg::FLAC::File, file);
DISPATCH_TAGLIB_FILE(TagLib::Ogg::Speex::File, file);
DISPATCH_TAGLIB_FILE(TagLib::MPC::File, file);
DISPATCH_TAGLIB_FILE(TagLib::WavPack::File, file);
#ifdef TAGLIB_WITH_ASF
DISPATCH_TAGLIB_FILE(TagLib::ASF::File, file);
#endif
#ifdef TAGLIB_WITH_MP4
DISPATCH_TAGLIB_FILE(TagLib::MP4::File, file);
#endif
DISPATCH_TAGLIB_FILE(TagLib::MPEG::File, file);
return string();
}
bool ReadTags(const string &filename, bool ignore_missing_mbid)
{
TagLib::FileRef file(filename.c_str(), true);
if (file.isNull())
return false;
TagLib::Tag *tags = file.tag();
TagLib::AudioProperties *props = file.audioProperties();
if (!tags || !props)
return false;
//cout << "ARTIST=" << tags->artist().to8Bit(true) << "\n";
//cout << "TITLE=" << tags->title().to8Bit(true) << "\n";
//cout << "ALBUM=" << tags->album().to8Bit(true) << "\n";
int length = props->length();
if (!length)
return false;
string mbid = ExtractMusicBrainzTrackID(file.file());
if (mbid.size() != 36 && !ignore_missing_mbid)
return false;
if (mbid.size() == 36)
cout << "MBID=" << mbid << "\n";
cout << "LENGTH=" << length << "\n";
cout << "BITRATE=" << props->bitrate() << "\n";
return true;
}
string ExtractExtension(const string &filename)
{
size_t pos = filename.find_last_of('.');
if (pos == string::npos) {
return string();
}
return boost::to_upper_copy(filename.substr(pos + 1));
}
string EncodeFingerprint(const vector<uint32_t> &fp)
{
string res;
res.resize(fp.size());
return res;
}
bool ProcessFile(Chromaprint::Fingerprinter *fingerprinter, const string &filename, bool ignore_missing_mbid, int audio_length)
{
if (!ReadTags(filename, ignore_missing_mbid))
return false;
Decoder decoder(filename);
if (!decoder.Open())
return false;
if (!fingerprinter->Start(decoder.SampleRate(), decoder.Channels()))
return false;
cerr << filename << "\n";
cout << "FILENAME=" << filename << "\n";
cout << "FORMAT=" << ExtractExtension(filename) << "\n";
decoder.Decode(fingerprinter, audio_length);
vector<int32_t> fp = fingerprinter->Finish();
/*cout << "FINGERPRINT1=";
for (int i = 0; i < fp.size(); i++) {
cout << fp[i] << ", ";
}
cout << "\n";*/
cout << "FINGERPRINT=" << Chromaprint::Base64Encode(Chromaprint::CompressFingerprint(fp, kChromaprintAlgorithm)) << "\n\n";
return true;
}
int main(int argc, char **argv)
{
if (argc < 2) {
cerr << "Usage: " << argv[0] << " [OPTIONS] FILE...\n";
cerr << "Options:\n";
cerr << " -nombid Do not require a MBID embedded in the file\n";
cerr << " -since DATE Process only files modified since the given date\n";
cerr << " -length SECONDS Length of the audio data used for fingerprinting (default 120)\n";
return 1;
}
string_vector files;
char *changed_since_str = NULL;
int audio_length = 120;
bool ignore_missing_mbid = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-nombid") == 0) {
ignore_missing_mbid = true;
}
else if (strcmp(argv[i], "-since") == 0 && i + 1 < argc) {
changed_since_str = argv[++i];
}
else if (strcmp(argv[i], "-length") == 0 && i + 1 < argc) {
audio_length = atoi(argv[++i]);
}
else {
files.push_back(argv[i]);
}
}
time_t changed_since = 0;
if (changed_since_str) {
struct tm tm;
memset(&tm, 0, sizeof(tm));
if (strptime(changed_since_str, "%Y-%m-%d %H:%M", &tm) == NULL) {
if (strptime(changed_since_str, "%Y-%m-%d", &tm) == NULL) {
cerr << "ERROR: Invalid date, the expected format is 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM'\n";
return 1;
}
}
tm.tm_isdst = -1;
changed_since = mktime(&tm);
//cerr << "Calculating fingerprints for files in " << files << " that were changed since " << changed_since_str << "\n";
}
else {
//cerr << "Calculating fingerprints for all files in " << files << "\n";
}
Chromaprint::Fingerprinter fingerprinter(Chromaprint::CreateFingerprinterConfiguration(kChromaprintAlgorithm));
files = FindFiles(files, changed_since);
for (string_vector::iterator it = files.begin(); it != files.end(); it++) {
ProcessFile(&fingerprinter, *it, ignore_missing_mbid, audio_length);
}
return 0;
}

View File

@ -1,142 +0,0 @@
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/multi_array.hpp>
#include "ext/ffmpeg_decoder.h"
#include "ext/image_utils.h"
#include "audio_processor.h"
#include "fingerprinter.h"
#include "image.h"
#include "integral_image.h"
#include "image_builder.h"
#include "utils.h"
#include "filter.h"
#include "lloyds.h"
#include "classifier.h"
#include "match.h"
using namespace std;
using namespace Chromaprint;
namespace fs = boost::filesystem;
typedef vector<string> string_vector;
typedef vector<double> double_vector;
string_vector FindAudioFiles(const char *dirname)
{
string_vector result;
fs::path path(dirname);
fs::directory_iterator end_iter;
for (fs::directory_iterator dir_iter(path); dir_iter != end_iter; ++dir_iter) {
if (fs::is_regular_file(dir_iter->status())) {
string filename = dir_iter->path().string();
if (boost::ends_with(filename, ".mp3") || boost::ends_with(filename, ".wav")) {
result.push_back(filename);
}
}
}
sort(result.begin(), result.end());
return result;
}
vector<string_vector> GenerateFilePairs(const vector<string> &files)
{
string last_name;
vector<string_vector> result;
for (int i = 0; i < files.size(); i++) {
string name = fs::basename(files[i]);
name = name.substr(0, name.find_first_of('-'));
if (last_name != name) {
result.push_back(string_vector());
last_name = name;
}
result.back().push_back(files[i]);
}
return result;
}
vector<int> MultiMapValues(const multimap<int, int> &data, const int &key)
{
pair<multimap<int, int>::const_iterator, multimap<int, int>::const_iterator> range = data.equal_range(key);
vector<int> result;
for (multimap<int, int>::const_iterator i = range.first; i != range.second; ++i) {
result.push_back((*i).second);
}
return result;
}
static const int SAMPLE_RATE = 11025;
static const int FRAME_SIZE = 4096;
static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720;
static const int MIN_FREQ = 28;
static const int MAX_FREQ = 3520;
static const int MAX_FILTER_WIDTH = 16;
/*static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 2;// 2720;
static const int MIN_FREQ = 300;
static const int MAX_FREQ = 5300;
static const int MAX_FILTER_WIDTH = 20;*/
void PrintRate(const std::string &name, const std::vector<int> &values, int scale)
{
cout << name << " = [";
for (int j = 0; j < 32; j++) {
double rate = double(values[j]) / scale;
if (j != 0) std::cout << ", ";
std::cout << rate;
}
cout << "]\n";
}
#define FP_TYPE_CHROMA 1
#define FP_TYPE_CENTROID 2
#define FP_TYPE FP_TYPE_CHROMA
int main(int argc, char **argv)
{
Chromaprint::Fingerprinter fingerprinter;
vector<string> files = FindAudioFiles(argv[1]);
vector< string > names[2];
vector< vector<int32_t> > fingerprints[2];
for (int i = 0; i < files.size(); i++) {
cout << " - " << files[i] << "\n";
Decoder decoder(files[i]);
if (!decoder.Open()) {
cerr << "ERROR: " << decoder.LastError() << "\n";
return 1;
}
fingerprinter.Start(decoder.SampleRate(), decoder.Channels());
decoder.Decode(&fingerprinter, 60);
vector<int32_t> fp = fingerprinter.Finish();
int orig = files[i].find("orig") != string::npos ? 1 : 0;
fingerprints[orig].push_back(fp);
names[orig].push_back(files[i]);
}
int num_files = files.size() / 2;
typedef boost::multi_array<float, 2> DoubleArray2D;
float total = 0.0f, diagonal = 0.0f;
DoubleArray2D confmatrix(boost::extents[num_files][num_files]);
for (int i = 0; i < num_files; i++) {
for (int j = 0; j < num_files; j++) {
float score = match_fingerprints(fingerprints[0][i], fingerprints[1][j]);
cout << " - " << names[0][i] << " / " << names[1][j] << " = " << score <<"\n";
confmatrix[i][j] = score;
if (i == j) {
diagonal += score;
}
total += score;
}
}
cout << "true positive: " << diagonal / num_files << "\n";
cout << "false positive: " << (total - diagonal) / (num_files * num_files - num_files) << "\n";
cout << "score: " << diagonal / total << "\n";
return 0;
}

View File

@ -1,121 +0,0 @@
#!/usr/bin/env python
import time
import sys
import urllib2
import urllib
import gzip
import socket
from cStringIO import StringIO
from optparse import OptionParser
usage = "usage: %prog [options] logfile"
parser = OptionParser(usage=usage)
parser.add_option("-a", "--api-key", dest="api_key", metavar="KEY",
help="your Acoustid API key (http://acoustid.org/api-key)")
parser.add_option("-b", "--batch-size", dest="batch_size", type="int",
default=50, metavar="SIZE",
help="how many fingerprints to submit in one request [default: %default]")
parser.add_option("--app-url", dest="app_url", type="string",
default='http://api.acoustid.org/submit',
help="how many fingerprints to submit in one request [default: %default]")
parser.add_option("--app-api-key", dest="app_api_key", type="string", default='5hOby2eZ',
help="application API key (needed only if you submit to a non-default URL)")
parser.add_option("-s", "--start", dest="start", type="int",
default=1, metavar="SIZE",
help="start with the Nth entry from the log file [default: %default]")
(options, args) = parser.parse_args()
if not options.api_key:
parser.error("no API key specified")
if len(args) != 1:
parser.error("no log file specified")
USER_API_KEY = options.api_key
CLIENT_API_KEY = options.app_api_key
API_URL = options.app_url
BATCH_SIZE = options.batch_size
def read_log_file(input):
group = {}
for line in input:
line = line.strip()
if not line:
if group:
yield group
group = {}
continue
name, value = line.split('=', 1)
group[name] = value
if group:
yield group
def encode_params(data):
encoded_body = StringIO()
encoded_file = gzip.GzipFile(mode='w', fileobj=encoded_body)
encoded_file.write(urllib.urlencode(data))
encoded_file.close()
return encoded_body.getvalue()
def submit_data(i, entries):
if not entries:
return True
params = { 'user': USER_API_KEY, 'client': CLIENT_API_KEY }
print 'Submitting... (entries from %d to %d)' % (i, i + len(entries) - 1)
i = 0
for entry in [e for e in entries if e['LENGTH'] >= 40 and len(e['FINGERPRINT'])>100]:
if 'MBID' not in entry and 'PUID' not in entry or int(entry.get('LENGTH', '0')) <= 0:
continue
if 'MBID' in entry:
print ' MBID ', entry['MBID'], entry['FINGERPRINT'][:20] + '...'
for mbid in entry['MBID'].split(','):
params['mbid.%d' % i] = mbid
if 'PUID' in entry:
print ' PUID ', entry['PUID'], entry['FINGERPRINT'][:20] + '...'
params['puid.%d' % i] = entry['PUID']
params['fingerprint.%d' % i] = entry['FINGERPRINT']
params['length.%d' % i] = entry['LENGTH']
if 'BITRATE' in entry:
params['bitrate.%d' % i] = entry['BITRATE']
if 'FORMAT' in entry:
params['format.%d' % i] = entry['FORMAT']
i += 1
data = encode_params(params)
request = urllib2.Request(API_URL, data, headers={'Content-Encoding': 'gzip'})
try:
urllib2.urlopen(request)
except urllib2.HTTPError, e:
print e
for line in e.readlines():
print line.rstrip()
return False
except urllib2.URLError, e:
print e
return False
except socket.error, e:
print e
return False
print 'OK'
return True
batch = []
i = options.start
j = 0
for entry in read_log_file(open(args[0]) if args[0] != '-' else sys.stdin):
j += 1
if j < options.start:
continue
batch.append(entry)
if len(batch) >= BATCH_SIZE:
submit_data(i, batch)
i = j
batch = []
time.sleep(0.1)
submit_data(i, batch)

View File

@ -1,396 +0,0 @@
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/dynamic_bitset.hpp>
#include "ext/ffmpeg_decoder.h"
#include "ext/image_utils.h"
#include "audio_processor.h"
#include "chroma.h"
#include "spectral_centroid.h"
#include "chroma_normalizer.h"
#include "chroma_resampler.h"
#include "chroma_filter.h"
#include "fft.h"
#include "audio_processor.h"
#include "image.h"
#include "integral_image.h"
#include "image_builder.h"
#include "utils.h"
#include "filter.h"
#include "lloyds.h"
#include "classifier.h"
using namespace std;
using namespace Chromaprint;
namespace fs = boost::filesystem;
typedef vector<string> string_vector;
typedef vector<double> double_vector;
string_vector FindAudioFiles(const char *dirname)
{
string_vector result;
fs::path path(dirname);
fs::directory_iterator end_iter;
for (fs::directory_iterator dir_iter(path); dir_iter != end_iter; ++dir_iter) {
if (fs::is_regular_file(dir_iter->status())) {
string filename = dir_iter->path().string();
if (boost::ends_with(filename, ".mp3") || boost::ends_with(filename, ".wma") || boost::ends_with(filename, ".wav")) {
result.push_back(filename);
}
}
}
sort(result.begin(), result.end());
return result;
}
vector<string_vector> GenerateFilePairs(const vector<string> &files)
{
string last_name;
vector<string_vector> result;
for (int i = 0; i < files.size(); i++) {
string name = fs::basename(files[i]);
name = name.substr(0, name.find_first_of('-'));
if (last_name != name) {
result.push_back(string_vector());
last_name = name;
}
result.back().push_back(files[i]);
}
return result;
}
vector<int> MultiMapValues(const multimap<int, int> &data, const int &key)
{
pair<multimap<int, int>::const_iterator, multimap<int, int>::const_iterator> range = data.equal_range(key);
vector<int> result;
for (multimap<int, int>::const_iterator i = range.first; i != range.second; ++i) {
result.push_back((*i).second);
}
return result;
}
static const int SAMPLE_RATE = 11025;
static const int FRAME_SIZE = 4096;
static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720;
static const int MIN_FREQ = 28;
static const int MAX_FREQ = 3520;
static const int MAX_FILTER_WIDTH = 16;
/*static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 2;// 2720;
static const int MIN_FREQ = 300;
static const int MAX_FREQ = 5300;
static const int MAX_FILTER_WIDTH = 20;*/
static const int TRAINING_SET_SIZE = 60000;
void PrintRate(const std::string &name, const std::vector<int> &values, int scale)
{
cout << name << " = [";
for (int j = 0; j < 32; j++) {
double rate = double(values[j]) / scale;
if (j != 0) std::cout << ", ";
std::cout << rate;
}
cout << "]\n";
}
#define FP_TYPE_CHROMA 1
#define FP_TYPE_CENTROID 2
#define FP_TYPE FP_TYPE_CHROMA
int main(int argc, char **argv)
{
Chromaprint::ImageBuilder image_builder;
#if FP_TYPE == FP_TYPE_CHROMA
Chromaprint::ChromaNormalizer chroma_normalizer(&image_builder);
static const double kChromaFilterCoeffs[] = { 0.25, 0.75, 1.0, 0.75, 0.25 };
Chromaprint::ChromaFilter chroma_filter(kChromaFilterCoeffs, 5, &chroma_normalizer);
Chromaprint::Chroma chroma(MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &chroma_filter);
//chroma.set_interpolate(true);
Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma);
#elif FP_TYPE == FP_TYPE_CHROMA
Chromaprint::SpectralCentroid centroid(16, MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &image_builder);
Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &centroid);
#endif
Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft);
cout << "Loading audio files\n";
vector<string_vector> files = GenerateFilePairs(FindAudioFiles(argv[1]));
vector<int> groups;
multimap<int, int> reverse_groups;
vector<Chromaprint::Image *> images;
vector<Chromaprint::IntegralImage *> integral_images;
for (int i = 0; i < files.size(); i++) {
//cout << i << ".\n";
for (int j = 0; j < files[i].size(); j++) {
cout << " - " << files[i][j] << "\n";
Decoder decoder(files[i][j]);
if (!decoder.Open()) {
cerr << "ERROR: " << decoder.LastError() << "\n";
return 1;
}
#if FP_TYPE == FP_TYPE_CHROMA
Image *image = new Image(12);
#elif FP_TYPE == FP_TYPE_CENTROID
Image *image = new Image(16);
#endif
processor.Reset(decoder.SampleRate(), decoder.Channels());
fft.Reset();
#if FP_TYPE == FP_TYPE_CHROMA
chroma.Reset();
chroma_filter.Reset();
chroma_normalizer.Reset();
#elif FP_TYPE == FP_TYPE_CENTROID
centroid.Reset();
#endif
image_builder.Reset(image);
decoder.Decode(&processor);
processor.Flush();
//ExportTextImage(image, files[i][j] + ".img.txt");
//Chromaprint::ExportImage(image_builder.image(), files[i][j] + ".img.png");
reverse_groups.insert(make_pair(i, images.size()));
groups.push_back(i);
images.push_back(image);
IntegralImage *int_image = new IntegralImage(image) ;
// ExportTextImage(int_image, files[i][j] + ".int_img.txt");
integral_images.push_back(int_image);
//ExportTextImage(int_image, files[i][j] + ".img.txt");
// return 1;
}
cout << images.size() << "\r";
cout.flush();
}
cout << "Training data set:\n";
cout << " - File groups: " << files.size() << "\n";
cout << " - Files: " << images.size() << "\n";
files.clear();
bool labels[TRAINING_SET_SIZE];
int data1[TRAINING_SET_SIZE];
int data2[TRAINING_SET_SIZE];
int data1_pos[TRAINING_SET_SIZE];
int data2_pos[TRAINING_SET_SIZE];
int i = 0;
srand(3);
// Find matching pairs
for (; i < TRAINING_SET_SIZE / 2; i++) {
int x1 = rand() % images.size();
vector<int> group = MultiMapValues(reverse_groups, groups[x1]);
int x2;
do {
x2 = group[rand() % group.size()];
} while (x1 == x2);
size_t min_length = min(images[x1]->NumRows(), images[x2]->NumRows());
int pos = rand() % (min_length - 30);
//cout << "+ " << x1 << " " << x2 << " - " << pos << "\n";
data1[i] = x1;
data2[i] = x2;
data1_pos[i] = pos;
data2_pos[i] = pos;
labels[i] = true;
}
// Find non-matching pairs
for (; i < TRAINING_SET_SIZE; i++) {
int x2, x1 = rand() % images.size();
int pos2, pos1 = rand() % (images[x1]->NumRows() - 30);
vector<int> group = MultiMapValues(reverse_groups, groups[x1]);
set<int> group_set(group.begin(), group.end());
do {
x2 = rand() % images.size();
pos2 = rand() % (images[x2]->NumRows() - 30);
} while (group_set.count(x2) && abs(pos1 - pos2) < 50);
//cout << "- " << x1 << " " << x2 << " - " << pos1 << " " << pos2 << "\n";
data1[i] = x1;
data2[i] = x2;
data1_pos[i] = pos1;
data2_pos[i] = pos2;
labels[i] = false;
}
const float maxWidth = 16.0;
const float widthScale = 1.0;
const float widthIncrement = 1.0;
const int numFilters = 6;
const int maxHeight = images[0]->NumColumns();
const int filterWidthInc[] = { 1, 1, 2, 2, 1, 3 };
const int filterHeightInc[] = { 1, 2, 1, 2, 3, 1 };
const int kNumCandidateQuantizers = 24;
double weights[TRAINING_SET_SIZE];
for (int i = 0; i < TRAINING_SET_SIZE; i++) {
weights[i] = 1.0 / TRAINING_SET_SIZE;
}
cout << "Computing filter responses\n";
std::vector<Filter> filters;
double *values_buffer = new double[100 * TRAINING_SET_SIZE * 2];
Filter flt;
FILE *f = fopen("filters.tmp", "wb");
for (int filter = 0; filter < numFilters; filter++) {
flt.set_type(filter);
for (int y = 0; y < maxHeight; y++) {
flt.set_y(y);
for (int h = filterHeightInc[filter]; h < maxHeight - y; h += filterHeightInc[filter]) {
flt.set_height(h);
int pw = 0;
for (int wf = filterWidthInc[filter]; wf <= maxWidth; wf += filterWidthInc[filter]) {
int w = wf;
if (pw == w)
continue;
flt.set_width(w);
fill(values_buffer, values_buffer + TRAINING_SET_SIZE * 2, 0.0);
for (int i = 0; i < TRAINING_SET_SIZE; i++) {
double value1 = flt.Apply(integral_images[data1[i]], data1_pos[i]);
double value2 = flt.Apply(integral_images[data2[i]], data2_pos[i]);
//cout << flt << " " << value1 << " [" << data1[i] << ":" << data1_pos[i] << "] " << value2 << " [" << data2[i] << ":" << data2_pos[i] << "]\n";
values_buffer[2*i+0] = value1;
values_buffer[2*i+1] = value2;
}
fwrite(values_buffer, sizeof(double), TRAINING_SET_SIZE * 2, f);
filters.push_back(flt);
}
}
}
}
cout << "Filters: " << filters.size() << "\n";
fclose(f);
f = fopen("filters.tmp", "rb");
cout << "Computing quantizers\n";
double *all_candidate_quantizers = new double[filters.size() * kNumCandidateQuantizers];
double *quantizer_ptr = all_candidate_quantizers;
fseek(f, 0, SEEK_SET);
double *values_ptr = values_buffer + 100 * TRAINING_SET_SIZE * 2;
for (int filter_i = 0; filter_i < filters.size(); filter_i++) {
int num_values = TRAINING_SET_SIZE * 2;
if (values_ptr >= values_buffer + 100 * TRAINING_SET_SIZE * 2) {
fread(values_buffer, sizeof(double), 100 * num_values, f);
values_ptr = values_buffer;
}
double_vector candidate_quantizers = lloyds(values_ptr, values_ptr + num_values, kNumCandidateQuantizers);
copy(candidate_quantizers.begin(), candidate_quantizers.end(), quantizer_ptr);
quantizer_ptr += kNumCandidateQuantizers;
values_ptr += num_values;
cout << filter_i << "\r";
cout.flush();
}
cout << "Running AdaBoost\n";
vector<Classifier> best_classifiers;
vector<double> best_classifiers_alpha;
int iteration = 0;
next_iteration:
double min_error = 1.0;
Classifier best_classifier;
boost::dynamic_bitset<> best_results(TRAINING_SET_SIZE);
fseek(f, 0, SEEK_SET);
quantizer_ptr = all_candidate_quantizers;
values_ptr = values_buffer + 100 * TRAINING_SET_SIZE * 2;
for (int filter_i = 0; filter_i < filters.size(); filter_i++) {
std::size_t num_values = TRAINING_SET_SIZE * 2;
if (values_ptr >= values_buffer + 100 * TRAINING_SET_SIZE * 2) {
fread(values_buffer, sizeof(double), 100 * num_values, f);
values_ptr = values_buffer;
}
Quantizer quantizer(0.0, 0.0, 0.0);
for (int ti0 = 0; ti0 < kNumCandidateQuantizers - 3; ti0++) {
quantizer.set_t0(quantizer_ptr[ti0]);
for (int ti1 = ti0 + 1; ti1 < kNumCandidateQuantizers - 2; ti1++) {
quantizer.set_t1(quantizer_ptr[ti1]);
for (int ti2 = ti1 + 1; ti2 < kNumCandidateQuantizers - 1; ti2++) {
quantizer.set_t2(quantizer_ptr[ti2]);
double error = 0.0;
for (int i = 0; i < TRAINING_SET_SIZE; i++) {
int q1 = quantizer.Quantize(values_ptr[i*2 + 0]);
int q2 = quantizer.Quantize(values_ptr[i*2 + 1]);
bool match = (q1 == q2) == labels[i];
if (!match) {
error += weights[i];
}
}
if (error < min_error) {
best_classifier = Classifier(filters[filter_i], quantizer);
min_error = error;
for (int i = 0; i < TRAINING_SET_SIZE; i++) {
int q1 = quantizer.Quantize(values_ptr[i*2 + 0]);
int q2 = quantizer.Quantize(values_ptr[i*2 + 1]);
bool match = (q1 == q2) == labels[i];
best_results[i] = match;
}
}
}
}
}
quantizer_ptr += kNumCandidateQuantizers;
values_ptr += num_values;
cout << filter_i << " [" << min_error << "] \r";
cout.flush();
}
double weight_sum = 0.0;
double alpha = 0.5 * log((1.0 - min_error) / min_error);
for (int i = 0; i < TRAINING_SET_SIZE; i++) {
weights[i] *= exp(-alpha * (best_results[i] ? 1.0 : -1.0));
weight_sum += weights[i];
}
for (int i = 0; i < TRAINING_SET_SIZE; i++) {
weights[i] /= weight_sum;
}
best_classifiers.push_back(best_classifier);
best_classifiers_alpha.push_back(alpha);
int wrong = 0;
int counts[2];
counts[0] = 0;
counts[1] = 0;
std::vector<int> bit_tp(32, 0);
std::vector<int> bit_fp(32, 0);
for (int i = 0; i < TRAINING_SET_SIZE; i++) {
double value = 0.0;
int bit_error = 0;
for (int j = 0; j < best_classifiers.size(); j++) {
int q1 = best_classifiers[j].Classify(integral_images[data1[i]], data1_pos[i]);
int q2 = best_classifiers[j].Classify(integral_images[data2[i]], data2_pos[i]);
int e = abs(q1 - q2);
bit_error += e == 3 ? 1 : e;
value += best_classifiers_alpha[j] * (q1 == q2 ? 1.0 : -1.0);
}
bool match = value > 0.0;
counts[labels[i]]++;
if (labels[i] != match) {
wrong += 1.0;
}
for (int j = 0; j < 32; j++) {
bool bit_match = bit_error <= j;
if (labels[i] && bit_match) {
bit_tp[j]++;
}
if (!labels[i] && bit_match) {
bit_fp[j]++;
}
}
}
++iteration;
cout << iteration << ". best classifier is " << best_classifier << " with error " << min_error << " (alpha " << alpha << "), final error is " << double(wrong) / TRAINING_SET_SIZE << "\n";
PrintRate("TP", bit_tp, counts[1]);
PrintRate("FP", bit_fp, counts[0]);
if (iteration < 16)
goto next_iteration;
return 0;
}

View File

@ -1,42 +0,0 @@
#include <vector>
#include <algorithm>
#include <stdint.h>
/* fingerprint matcher settings */
#define ACOUSTID_MAX_BIT_ERROR 2
#define ACOUSTID_MAX_ALIGN_OFFSET 120
#define BITCOUNT(x) __builtin_popcount(x)
inline float
match_fingerprints(const std::vector<int32_t> &a, const std::vector<int32_t> &b)
{
int i, j, topcount;
int maxsize = std::max(a.size(), b.size());
int numcounts = maxsize * 2 + 1;
int *counts = (int*)malloc(sizeof(int) * numcounts);
memset(counts, 0, sizeof(int) * numcounts);
for (i = 0; i < a.size(); i++) {
int jbegin = std::max(0, i - ACOUSTID_MAX_ALIGN_OFFSET);
int jend = std::min(b.size(), size_t(i + ACOUSTID_MAX_ALIGN_OFFSET));
for (j = jbegin; j < jend; j++) {
int biterror = BITCOUNT(a[i] ^ b[j]);
if (biterror <= ACOUSTID_MAX_BIT_ERROR) {
int offset = i - j + maxsize;
counts[offset]++;
}
}
}
topcount = 0;
for (i = 0; i < numcounts; i++) {
if (counts[i] > topcount) {
topcount = counts[i];
}
}
free(counts);
return (float)topcount / std::min(a.size(), b.size());
}

View File

@ -1,13 +0,0 @@
#!/bin/bash
for FILE in `ls *-orig.wav`; do
TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-128mp3.mp3/'`
NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-128mp3.wav/'`
if [ ! -f $NEWFILE ]; then
rm -f $NEWFILE
ffmpeg -i $FILE -ab 128000 $TMPNEWFILE
ffmpeg -i $TMPNEWFILE $NEWFILE
rm -f $TMPNEWFILE
fi
done

View File

@ -1,13 +0,0 @@
#!/bin/bash
for FILE in `ls *-orig.wav`; do
TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-32mp3.mp3/'`
NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-32mp3.wav/'`
if [ ! -f $NEWFILE ]; then
rm -f $NEWFILE
ffmpeg -i $FILE -ab 32000 $TMPNEWFILE
ffmpeg -i $TMPNEWFILE $NEWFILE
rm -f $TMPNEWFILE
fi
done

View File

@ -1,13 +0,0 @@
#!/bin/bash
for FILE in `ls *-orig.wav`; do
TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64mp3.mp3/'`
NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64mp3.wav/'`
if [ ! -f $NEWFILE ]; then
rm -f $NEWFILE
ffmpeg -i $FILE -ab 64000 $TMPNEWFILE
ffmpeg -i $TMPNEWFILE $NEWFILE
rm -f $TMPNEWFILE
fi
done

View File

@ -1,13 +0,0 @@
#!/bin/bash
for FILE in `ls *-orig.wav`; do
TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64wma.wma/'`
NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-64wma.wav/'`
if [ ! -f $NEWFILE ]; then
rm -f $NEWFILE
ffmpeg -i $FILE -ab 64000 -acodec wmav2 $TMPNEWFILE
ffmpeg -i $TMPNEWFILE $NEWFILE
rm -f $TMPNEWFILE
fi
done

View File

@ -1,17 +0,0 @@
#!/bin/bash
for FILE in `ls *-orig.wav`; do
TMP1FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp.wav/'`
TMP2FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp2.wav/'`
TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-gain.wma/'`
NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-gain.wav/'`
if [ ! -f $NEWFILE ]; then
rm -f $NEWFILE $TMP1FILE $TMP2FILE
ffmpeg -i $FILE $TMP1FILE
sox $TMP1FILE $TMP2FILE gain -n -10
ffmpeg -i $TMP2FILE -ab 128000 -acodec wmav2 $TMPNEWFILE
ffmpeg -i $TMPNEWFILE $NEWFILE
rm -f $TMP1FILE $TMP2FILE $TMPNEWFILE
fi
done

View File

@ -1,15 +0,0 @@
#!/bin/bash
for FILE in `ls *-orig.wav`; do
TMP1FILE=`echo $FILE | perl -pe 's/-orig\..*$/-tmp.wav/'`
TMPNEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-resample.wma/'`
NEWFILE=`echo $FILE | perl -pe 's/-orig\..*$/-resample.wav/'`
if [ ! -f $NEWFILE ]; then
rm -f $NEWFILE $TMP1FILE $TMPNEWFILE
sox $FILE $TMP1FILE rate -l 8k
ffmpeg -i $TMP1FILE -ab 128000 -acodec wmav2 $TMPNEWFILE
ffmpeg -i $TMPNEWFILE $NEWFILE
rm -f $TMP1FILE $TMPNEWFILE
fi
done

View File

@ -1,9 +0,0 @@
#!/bin/bash
for FILE in `ls *.{mp3,wma,ogg}`; do
NEWFILE=`echo $FILE | perl -pe 's/\..*$/.wav/'`
rm -f $NEWFILE
ffmpeg -i $FILE $NEWFILE
rm -f $FILE
done

View File

@ -1,9 +0,0 @@
#!/bin/bash
cp orig/*.wav .
./prepare-32mp3.sh
./prepare-64mp3.sh
./prepare-128mp3.sh
./prepare-64wma.sh
./prepare-gain.sh
./prepare-wav.sh

View File

@ -1,35 +0,0 @@
#include <string>
#include <iostream>
using namespace std;
#include "ext/ffmpeg_decoder.h"
#include "ext/audio_dumper.h"
#include "audio_processor.h"
int main(int argc, char **argv)
{
if (argc < 2) {
cerr << "Usage: " << argv[0] << " FILENAME\n";
return 1;
}
string file_name(argv[1]);
cout << "Loading file " << file_name << "\n";
Decoder decoder(file_name);
if (!decoder.Open()) {
cerr << "ERROR: " << decoder.LastError() << "\n";
return 2;
}
AudioDumper dumper("resampled.raw");
Chromaprint::AudioProcessor processor(11025, &dumper);
processor.Reset(decoder.SampleRate(), decoder.Channels());
decoder.Decode(&processor);
processor.Flush();
return 0;
}

View File

@ -1,63 +0,0 @@
#include <string>
#include <iostream>
using namespace std;
#include "ext/ffmpeg_decoder.h"
#include "ext/audio_dumper.h"
#include "audio_processor.h"
#include "chroma.h"
#include "spectrum.h"
#include "chroma_normalizer.h"
#include "chroma_resampler.h"
#include "chroma_filter.h"
#include "fft.h"
#include "audio_processor.h"
#include "image.h"
#include "image_builder.h"
#include "utils.h"
#include "ext/image_utils.h"
static const int SAMPLE_RATE = 11025;
static const int FRAME_SIZE = 4096;
static const int OVERLAP = FRAME_SIZE - FRAME_SIZE / 3;// 2720;
static const int MIN_FREQ = 28;
static const int MAX_FREQ = 3520;
static const int MAX_FILTER_WIDTH = 20;
static const int kChromaFilterSize = 5;
static const double kChromaFilterCoefficients[] = { 0.25, 0.75, 1.0, 0.75, 0.25 };
int main(int argc, char **argv)
{
if (argc < 3) {
cerr << "Usage: " << argv[0] << " AUDIOFILE IMAGEFILE\n";
return 1;
}
string file_name(argv[1]);
cout << "Loading file " << file_name << "\n";
Decoder decoder(file_name);
if (!decoder.Open()) {
cerr << "ERROR: " << decoder.LastError() << "\n";
return 2;
}
const int numBands = 72;
Chromaprint::Image image(numBands);
Chromaprint::ImageBuilder image_builder(&image);
Chromaprint::Spectrum chroma(numBands, MIN_FREQ, MAX_FREQ, FRAME_SIZE, SAMPLE_RATE, &image_builder);
Chromaprint::FFT fft(FRAME_SIZE, OVERLAP, &chroma);
Chromaprint::AudioProcessor processor(SAMPLE_RATE, &fft);
processor.Reset(decoder.SampleRate(), decoder.Channels());
decoder.Decode(&processor);
processor.Flush();
//Chromaprint::ExportTextImage(&image, argv[2]);
Chromaprint::ExportImage(&image, argv[2], 0.5);
return 0;
}