Merge branch 'master' into webremote

This commit is contained in:
John Maguire 2015-01-19 11:49:47 +01:00
commit 50abf41609
680 changed files with 93321 additions and 63315 deletions

View File

@ -1,38 +0,0 @@
CMakeFiles
CMakeCache.txt
Makefile
cmake_install.cmake
config.h
tests/all_tests
tools/fpgen
tools/fpcollect
*.exe
*.dll
*.so
*.a
tools/fpeval
tools/learn_filters
tools/decode
tools/chromagram
tools/resample
libchromaprint.pc
install_manifest.txt
tools/spectrogram
src/libchromaprint.so.*
*.vcxproj
*.vcxproj.*
*.dir
*.sln
*.suo
Debug
src/Debug
*.dll
*.lib
*.pdb
*.dll.manifest
*.exp
*.dylib
*.vcproj
*.user
*.ncb
src/Release

View File

@ -103,7 +103,7 @@ if(WITH_FFTW3)
message(STATUS "Using FFTW3 for FFT calculations")
endif(WITH_FFTW3)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/chromaprint_config.h)
add_subdirectory(src)

View File

@ -26,7 +26,7 @@
* modification -- Lennart */
#if defined(HAVE_CONFIG_H)
#include <config.h>
#include <chromaprint_config.h>
#endif
#include <sys/types.h>

View File

@ -22,7 +22,7 @@
#define CHROMAPRINT_FFT_LIB_H_
#ifdef HAVE_CONFIG_H
#include <config.h>
#include <chromaprint_config.h>
#endif
#ifdef WITH_AVFFT

View File

@ -18,6 +18,10 @@
* USA
*/
extern "C" {
#include <libavutil/mem.h>
}
#include "utils.h"
#include "fft_lib_avfft.h"

View File

@ -21,9 +21,7 @@
#ifndef CHROMAPRINT_FFT_LIB_AVFFT_H_
#define CHROMAPRINT_FFT_LIB_AVFFT_H_
#include <math.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavcodec/avfft.h>
}
#include "combined_buffer.h"

View File

View File

@ -22,7 +22,7 @@
#define CHROMAPRINT_UTILS_H_
#if defined(HAVE_CONFIG_H)
#include <config.h>
#include <chromaprint_config.h>
#endif
#include <math.h>

View File

@ -107,6 +107,7 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile");
lockFile.setFileName(lockName);
lockFileCreated = !lockFile.exists();
lockFile.open(QIODevice::ReadWrite);
}
@ -212,5 +213,6 @@ void QtLocalPeer::receiveConnection()
QtLocalPeer::~QtLocalPeer ()
{
lockFile.remove();
if (lockFileCreated)
lockFile.remove();
}

View File

@ -81,4 +81,5 @@ protected:
private:
static const char* ack;
bool lockFileCreated;
};

483
3rdparty/sha2/sha2.cpp vendored
View File

@ -126,8 +126,6 @@ typedef u_int64_t sha2_word64; /* Exactly 8 bytes */
/*** SHA-256/384/512 Various Length Definitions ***********************/
/* NOTE: Most of these are in sha2.h */
#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16)
#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
/*** ENDIAN REVERSAL MACROS *******************************************/
@ -200,8 +198,6 @@ typedef u_int64_t sha2_word64; /* Exactly 8 bytes */
#define R(b,x) ((x) >> (b))
/* 32-bit Rotate-right (used in SHA-256): */
#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
@ -213,20 +209,12 @@ typedef u_int64_t sha2_word64; /* Exactly 8 bytes */
#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
/* Four of six logical functions used in SHA-384 and SHA-512: */
#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
/*** INTERNAL FUNCTION PROTOTYPES *************************************/
/* NOTE: These should not be accessed directly from outside this
* library -- they are intended for private internal visibility/use
* only.
*/
void SHA512_Last(SHA512_CTX*);
void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
void SHA512_Transform(SHA512_CTX*, const sha2_word64*);
/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
@ -262,73 +250,6 @@ const static sha2_word32 sha256_initial_hash_value[8] = {
0x5be0cd19UL
};
/* Hash constant words K for SHA-384 and SHA-512: */
const static sha2_word64 K512[80] = {
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
};
/* Initial hash value H for SHA-384 */
const static sha2_word64 sha384_initial_hash_value[8] = {
0xcbbb9d5dc1059ed8ULL,
0x629a292a367cd507ULL,
0x9159015a3070dd17ULL,
0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL,
0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL,
0x47b5481dbefa4fa4ULL
};
/* Initial hash value H for SHA-512 */
const static sha2_word64 sha512_initial_hash_value[8] = {
0x6a09e667f3bcc908ULL,
0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL,
0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL,
0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL,
0x5be0cd19137e2179ULL
};
/*
* Constant used by SHA256/384/512_End() functions for converting the
@ -664,408 +585,4 @@ char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_S
return SHA256_End(&context, digest);
}
/*** SHA-512: *********************************************************/
void SHA512_Init(SHA512_CTX* context) {
if (context == (SHA512_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-512 round macros: */
#if BYTE_ORDER == LITTLE_ENDIAN
#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
REVERSE64(*data++, W512[j]); \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
K512[j] + W512[j]; \
(d) += T1, \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \
j++
#else /* BYTE_ORDER == LITTLE_ENDIAN */
#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \
K512[j] + (W512[j] = *data++); \
(d) += T1; \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
j++
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
#define ROUND512(a,b,c,d,e,f,g,h) \
s0 = W512[(j+1)&0x0f]; \
s0 = sigma0_512(s0); \
s1 = W512[(j+14)&0x0f]; \
s1 = sigma1_512(s1); \
T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
j++
void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
sha2_word64 T1, *W512 = (sha2_word64*)context->buffer;
int j;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds up to 79: */
do {
ROUND512(a,b,c,d,e,f,g,h);
ROUND512(h,a,b,c,d,e,f,g);
ROUND512(g,h,a,b,c,d,e,f);
ROUND512(f,g,h,a,b,c,d,e);
ROUND512(e,f,g,h,a,b,c,d);
ROUND512(d,e,f,g,h,a,b,c);
ROUND512(c,d,e,f,g,h,a,b);
ROUND512(b,c,d,e,f,g,h,a);
} while (j < 80);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) {
sha2_word64 a, b, c, d, e, f, g, h, s0, s1;
sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer;
int j;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
#if BYTE_ORDER == LITTLE_ENDIAN
/* Convert TO host byte order */
REVERSE64(*data++, W512[j]);
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
#else /* BYTE_ORDER == LITTLE_ENDIAN */
/* Apply the SHA-512 compression function to update a..h with copy */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++);
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W512[(j+1)&0x0f];
s0 = sigma0_512(s0);
s1 = W512[(j+14)&0x0f];
s1 = sigma1_512(s1);
/* Apply the SHA-512 compression function to update a..h */
T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
(W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
T2 = Sigma0_512(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 80);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
unsigned int freespace, usedspace;
if (len == 0) {
/* Calling with no data is valid - we do nothing */
return;
}
/* Sanity check: */
assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA512_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace);
ADDINC128(context->bitcount, freespace << 3);
len -= freespace;
data += freespace;
SHA512_Transform(context, (sha2_word64*)context->buffer);
} else {
/* The buffer is not yet full */
MEMCPY_BCOPY(&context->buffer[usedspace], data, len);
ADDINC128(context->bitcount, len << 3);
/* Clean up: */
usedspace = freespace = 0;
return;
}
}
while (len >= SHA512_BLOCK_LENGTH) {
/* Process as many complete blocks as we can */
SHA512_Transform(context, (sha2_word64*)data);
ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
len -= SHA512_BLOCK_LENGTH;
data += SHA512_BLOCK_LENGTH;
}
if (len > 0) {
/* There's left-overs, so save 'em */
MEMCPY_BCOPY(context->buffer, data, len);
ADDINC128(context->bitcount, len << 3);
}
/* Clean up: */
usedspace = freespace = 0;
}
void SHA512_Last(SHA512_CTX* context) {
unsigned int usedspace;
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
#if BYTE_ORDER == LITTLE_ENDIAN
/* Convert FROM host byte order */
REVERSE64(context->bitcount[0],context->bitcount[0]);
REVERSE64(context->bitcount[1],context->bitcount[1]);
#endif
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
} else {
if (usedspace < SHA512_BLOCK_LENGTH) {
MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
}
/* Do second-to-last transform: */
SHA512_Transform(context, (sha2_word64*)context->buffer);
/* And set-up for the last transform: */
MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2);
}
} else {
/* Prepare for final transform: */
MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Store the length of input data (in bits): */
*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
*(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
/* Final transform: */
SHA512_Transform(context, (sha2_word64*)context->buffer);
}
void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
assert(context != (SHA512_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
SHA512_Last(context);
/* Save the hash data for output: */
#if BYTE_ORDER == LITTLE_ENDIAN
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 8; j++) {
REVERSE64(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH);
#endif
}
/* Zero out state data */
MEMSET_BZERO(context, sizeof(SHA512_CTX));
}
char *SHA512_End(SHA512_CTX* context, char buffer[]) {
sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest;
int i;
/* Sanity check: */
assert(context != (SHA512_CTX*)0);
if (buffer != (char*)0) {
SHA512_Final(digest, context);
for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
*buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
*buffer++ = sha2_hex_digits[*d & 0x0f];
d++;
}
*buffer = (char)0;
} else {
MEMSET_BZERO(context, sizeof(SHA512_CTX));
}
MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH);
return buffer;
}
char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) {
SHA512_CTX context;
SHA512_Init(&context);
SHA512_Update(&context, data, len);
return SHA512_End(&context, digest);
}
/*** SHA-384: *********************************************************/
void SHA384_Init(SHA384_CTX* context) {
if (context == (SHA384_CTX*)0) {
return;
}
MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH);
MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH);
context->bitcount[0] = context->bitcount[1] = 0;
}
void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
SHA512_Update((SHA512_CTX*)context, data, len);
}
void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
assert(context != (SHA384_CTX*)0);
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != (sha2_byte*)0) {
SHA512_Last((SHA512_CTX*)context);
/* Save the hash data for output: */
#if BYTE_ORDER == LITTLE_ENDIAN
{
/* Convert TO host byte order */
int j;
for (j = 0; j < 6; j++) {
REVERSE64(context->state[j],context->state[j]);
*d++ = context->state[j];
}
}
#else
MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH);
#endif
}
/* Zero out state data */
MEMSET_BZERO(context, sizeof(SHA384_CTX));
}
char *SHA384_End(SHA384_CTX* context, char buffer[]) {
sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest;
int i;
/* Sanity check: */
assert(context != (SHA384_CTX*)0);
if (buffer != (char*)0) {
SHA384_Final(digest, context);
for (i = 0; i < SHA384_DIGEST_LENGTH; i++) {
*buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
*buffer++ = sha2_hex_digits[*d & 0x0f];
d++;
}
*buffer = (char)0;
} else {
MEMSET_BZERO(context, sizeof(SHA384_CTX));
}
MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH);
return buffer;
}
char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) {
SHA384_CTX context;
SHA384_Init(&context);
SHA384_Update(&context, data, len);
return SHA384_End(&context, digest);
}
} // namespace clementine_sha2

25
3rdparty/sha2/sha2.h vendored
View File

@ -48,12 +48,6 @@ namespace clementine_sha2 {
static const int SHA256_BLOCK_LENGTH = 64;
static const int SHA256_DIGEST_LENGTH = 32;
static const int SHA256_DIGEST_STRING_LENGTH = (SHA256_DIGEST_LENGTH * 2 + 1);
static const int SHA384_BLOCK_LENGTH = 128;
static const int SHA384_DIGEST_LENGTH = 48;
static const int SHA384_DIGEST_STRING_LENGTH = (SHA384_DIGEST_LENGTH * 2 + 1);
static const int SHA512_BLOCK_LENGTH = 128;
static const int SHA512_DIGEST_LENGTH = 64;
static const int SHA512_DIGEST_STRING_LENGTH = (SHA512_DIGEST_LENGTH * 2 + 1);
/*** SHA-256/384/512 Context Structures *******************************/
@ -72,13 +66,6 @@ typedef struct _SHA256_CTX {
u_int64_t bitcount;
u_int8_t buffer[SHA256_BLOCK_LENGTH];
} SHA256_CTX;
typedef struct _SHA512_CTX {
u_int64_t state[8];
u_int64_t bitcount[2];
u_int8_t buffer[SHA512_BLOCK_LENGTH];
} SHA512_CTX;
typedef SHA512_CTX SHA384_CTX;
void SHA256_Init(SHA256_CTX *);
@ -87,18 +74,6 @@ void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*);
char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]);
char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]);
void SHA384_Init(SHA384_CTX*);
void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t);
void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*);
char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]);
char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]);
void SHA512_Init(SHA512_CTX*);
void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t);
void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]);
char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]);
} // namespace clementine_sha2
#endif /* __CLEMENTINE_SHA2_H__ */

View File

@ -433,9 +433,24 @@ long MPEG::File::firstFrameOffset()
{
long position = 0;
if(ID3v2Tag())
if(ID3v2Tag()) {
position = d->ID3v2Location + ID3v2Tag()->header()->completeTagSize();
// Skip duplicate ID3v2 tags.
// Workaround for some faulty files that have duplicate ID3v2 tags.
// Combination of EAC and LAME creates such files when configured incorrectly.
long location;
while((location = findID3v2(position)) >= 0) {
seek(location);
const ID3v2::Header header(readBlock(ID3v2::Header::size()));
position = location + header.completeTagSize();
debug("MPEG::File::firstFrameOffset() - Duplicate ID3v2 tag found.");
}
}
return nextFrameOffset(position);
}
@ -467,7 +482,7 @@ void MPEG::File::read(bool readProperties, Properties::ReadStyle propertiesStyle
{
// Look for an ID3v2 tag
d->ID3v2Location = findID3v2();
d->ID3v2Location = findID3v2(0);
if(d->ID3v2Location >= 0) {
@ -510,7 +525,7 @@ void MPEG::File::read(bool readProperties, Properties::ReadStyle propertiesStyle
ID3v1Tag(true);
}
long MPEG::File::findID3v2()
long MPEG::File::findID3v2(long offset)
{
// This method is based on the contents of TagLib::File::find(), but because
// of some subtlteies -- specifically the need to look for the bit pattern of
@ -534,9 +549,9 @@ long MPEG::File::findID3v2()
long originalPosition = tell();
// Start the search at the beginning of the file.
// Start the search at the offset.
seek(0);
seek(offset);
// This loop is the crux of the find method. There are three cases that we
// want to account for:
@ -547,7 +562,7 @@ long MPEG::File::findID3v2()
// (2) The search pattern is wholly contained within the current buffer.
//
// (3) The current buffer ends with a partial match of the pattern. We will
// note this for use in the next itteration, where we will check for the rest
// note this for use in the next iteration, where we will check for the rest
// of the pattern.
for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) {
@ -561,7 +576,7 @@ long MPEG::File::findID3v2()
const int patternOffset = (bufferSize() - previousPartialMatch);
if(buffer.containsAt(ID3v2::Header::fileIdentifier(), 0, patternOffset)) {
seek(originalPosition);
return bufferOffset - bufferSize() + previousPartialMatch;
return offset + bufferOffset - bufferSize() + previousPartialMatch;
}
}
@ -570,7 +585,7 @@ long MPEG::File::findID3v2()
long location = buffer.find(ID3v2::Header::fileIdentifier());
if(location >= 0) {
seek(originalPosition);
return bufferOffset + location;
return offset + bufferOffset + location;
}
int firstSynchByte = buffer.find(char(uchar(255)));

View File

@ -242,8 +242,8 @@ namespace TagLib {
* if there is no valid ID3v2 tag. If \a create is true it will create
* an ID3v2 tag if one does not exist and returns a valid pointer.
*
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file
* on disk actually has an ID3v2 tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
@ -261,8 +261,8 @@ namespace TagLib {
* if there is no valid ID3v1 tag. If \a create is true it will create
* an ID3v1 tag if one does not exist and returns a valid pointer.
*
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
* on disk actually has an ID3v1 tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
@ -280,8 +280,8 @@ namespace TagLib {
* if there is no valid APE tag. If \a create is true it will create
* an APE tag if one does not exist and returns a valid pointer.
*
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an APE tag. Use hasAPETag() to check if the file
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an APE tag. Use hasAPETag() to check if the file
* on disk actually has an APE tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
@ -370,7 +370,7 @@ namespace TagLib {
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
long findID3v2();
long findID3v2(long offset);
long findID3v1();
void findAPE();

View File

@ -102,9 +102,6 @@ macro(UPDATE_COMPILER_FLAGS target)
elseif(${target}_TYPE STREQUAL "SHARED_LIBRARY")
update_cxx_compiler_flag(${target} "-fvisibility=hidden" HIDDEN_VISIBILITY)
endif()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
update_cxx_compiler_flag(${target} "-flto" LTO)
endif()
set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${COMPILER_FLAGS}")
endmacro()

View File

@ -210,6 +210,29 @@ IntReply *AudioProvider::removeFromLibrary(int aid, int oid)
return reply;
}
IdListReply *AudioProvider::setBroadcast(int aid, int oid, const IdList &targetIds)
{
Q_D(AudioProvider);
QVariantMap args;
args.insert("audio", QString("%1_%2").arg(oid).arg(aid));
args.insert("target_ids", join(targetIds));
auto reply = d->client->request<IdListReply>("audio.setBroadcast", args, ReplyPrivate::handleIdList);
return reply;
}
IdListReply *AudioProvider::resetBroadcast(const IdList &targetIds)
{
Q_D(AudioProvider);
QVariantMap args;
args.insert("audio","");
args.insert("target_ids", join(targetIds));
auto reply = d->client->request<IdListReply>("audio.setBroadcast", args, ReplyPrivate::handleIdList);
return reply;
}
AudioItemListReply *AudioProvider::getAudiosByIds(const QString &ids)
{
Q_D(AudioProvider);

View File

@ -26,6 +26,7 @@
#define VK_AUDIO_H
#include <QAbstractListModel>
#include "vk_global.h"
#include "audioitem.h"
#include "abstractlistmodel.h"
#include "reply.h"
@ -35,6 +36,7 @@ namespace Vreen {
class Client;
typedef ReplyBase<AudioItemList> AudioItemListReply;
typedef ReplyBase<AudioAlbumItemList> AudioAlbumItemListReply;
typedef ReplyBase<QList<int>> IdListReply;
class AudioProviderPrivate;
class VK_SHARED_EXPORT AudioProvider : public QObject
@ -60,6 +62,8 @@ public:
IntReply *getCount(int oid = 0);
IntReply *addToLibrary(int aid, int oid, int gid = 0);
IntReply *removeFromLibrary(int aid, int oid);
IdListReply *setBroadcast(int aid, int oid, const IdList& targetIds);
IdListReply *resetBroadcast(const IdList& targetIds);
protected:
QScopedPointer<AudioProviderPrivate> d_ptr;
};

View File

@ -122,6 +122,16 @@ void ReplyPrivate::_q_network_reply_error(QNetworkReply::NetworkError code)
emit q->resultReady(response);
}
QVariant ReplyPrivate::handleIdList(const QVariant &response)
{
IdList ids;
auto list = response.toList();
foreach (auto item, list) {
ids.append(item.toInt());
}
return QVariant::fromValue(ids);
}
QVariant MessageListHandler::operator()(const QVariant &response)
{

View File

@ -50,15 +50,16 @@ public:
void _q_reply_finished();
void _q_network_reply_error(QNetworkReply::NetworkError);
static QVariant handleInt(const QVariant &response) { return response.toInt(); }
static QVariant handleInt(const QVariant &response) { return response.toInt(); }
static QVariant handleIdList(const QVariant& response);
};
struct MessageListHandler {
MessageListHandler(int clientId) : clientId(clientId) {}
QVariant operator()(const QVariant &response);
MessageListHandler(int clientId) : clientId(clientId) {}
QVariant operator()(const QVariant &response);
int clientId;
int clientId;
};
} //namespace Vreen

View File

@ -3,6 +3,7 @@ cmake_policy(SET CMP0011 OLD)
include(CheckCXXCompilerFlag)
include(FindPkgConfig)
include(cmake/C++11Compat.cmake)
include(cmake/Summary.cmake)
include(cmake/Version.cmake)
include(cmake/Deb.cmake)
@ -21,6 +22,13 @@ if (APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --stdlib=libc++")
endif ()
find_program(CCACHE_EXECUTABLE NAMES ccache)
if (CCACHE_EXECUTABLE)
message(STATUS "ccache found: will be used for compilation and linkage")
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_EXECUTABLE})
SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_EXECUTABLE})
endif ()
if (UNIX AND NOT APPLE)
set(LINUX 1)
endif (UNIX AND NOT APPLE)
@ -49,11 +57,11 @@ pkg_check_modules(CHROMAPRINT libchromaprint)
pkg_check_modules(GIO gio-2.0)
pkg_check_modules(GLIB glib-2.0)
pkg_check_modules(GOBJECT gobject-2.0)
pkg_check_modules(GSTREAMER gstreamer-0.10)
pkg_check_modules(GSTREAMER_APP gstreamer-app-0.10)
pkg_check_modules(GSTREAMER_BASE gstreamer-base-0.10)
pkg_check_modules(GSTREAMER_CDDA gstreamer-cdda-0.10)
pkg_check_modules(GSTREAMER_TAG gstreamer-tag-0.10)
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
pkg_check_modules(GSTREAMER_APP REQUIRED gstreamer-app-1.0)
pkg_check_modules(GSTREAMER_AUDIO REQUIRED gstreamer-audio-1.0)
pkg_check_modules(GSTREAMER_BASE REQUIRED gstreamer-base-1.0)
pkg_check_modules(GSTREAMER_TAG REQUIRED gstreamer-tag-1.0)
pkg_check_modules(INDICATEQT indicate-qt)
pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92)
pkg_check_modules(LIBMTP libmtp>=1.0)
@ -140,8 +148,8 @@ include_directories(${TAGLIB_INCLUDE_DIRS})
include_directories(${QJSON_INCLUDE_DIRS})
include_directories(${GSTREAMER_INCLUDE_DIRS})
include_directories(${GSTREAMER_APP_INCLUDE_DIRS})
include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS})
include_directories(${GSTREAMER_BASE_INCLUDE_DIRS})
include_directories(${GSTREAMER_CDDA_INCLUDE_DIRS})
include_directories(${GSTREAMER_TAG_INCLUDE_DIRS})
include_directories(${GLIB_INCLUDE_DIRS})
include_directories(${GLIBCONFIG_INCLUDE_DIRS})
@ -199,6 +207,11 @@ optional_component(BOX ON "Box support"
optional_component(VK ON "Vk.com support")
optional_component(SEAFILE ON "Seafile support"
DEPENDS "Google sparsehash" SPARSEHASH_INCLUDE_DIRS
DEPENDS "Taglib 1.8" "TAGLIB_VERSION VERSION_GREATER 1.7.999"
)
optional_component(AUDIOCD ON "Devices: Audio CD support"
DEPENDS "libcdio" CDIO_FOUND
)
@ -368,10 +381,19 @@ if(GMOCK_INCLUDE_DIRS)
endif(GTEST_INCLUDE_DIRS)
endif(GMOCK_INCLUDE_DIRS)
# Never use the system's sha2.
add_subdirectory(3rdparty/sha2)
set(SHA2_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/sha2)
set(SHA2_LIBRARIES sha2)
# Use the system's sha2 if it's available.
find_path(SHA2_INCLUDE_DIRS sha2.h)
find_library(SHA2_LIBRARIES sha2)
if(SHA2_LIBRARIES AND SHA2_INCLUDE_DIRS)
message(STATUS "Using system sha2 library")
set(USE_SYSTEM_SHA2 ON)
else()
message(STATUS "Using builtin sha2 library")
set(USE_SYSTEM_SHA2 OFF)
add_subdirectory(3rdparty/sha2)
set(SHA2_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/sha2)
set(SHA2_LIBRARIES sha2)
endif()
# Use our 3rdparty chromaprint if a system one wasn't found
if(NOT CHROMAPRINT_FOUND)

View File

@ -1,3 +1,101 @@
Version 1.3:
Major features:
* Vk.com support
* Seafile support
* Add Ampache compatibility (through Subsonic service)
* Add new analyzer "Rainbow Dash"
* Answer to the ultimate question of life, the universe and everything
Other features:
* Add left click to fullsize cover on playing widget
* Add m4b support for non-drm files
* Ignore english articles for library sorting
* Previous track in dynamic random mix
* Improve the organize dialog
* Add playlist save preference
* Add a preference to disable the pause notification
* Add a preference tab to hide some internet services
* Add an option to disable inline song metadata editing
* Use a save dialog option instead of quick change menu
* Add ability to fetch lyrics from lololyrics.com
* Add support for monitors in portrait mode
* Add now playing widget mode
* Add icons to extra
* Add a source icon for CD tracks
* Allow user to remove directories
* Add ability to remove unavailable items from playlist
* Adds an import button to the transcode UI, allowing the user to pull in
all files in a folder heirarchy to be transcoded
* Allow user to pull in all files in a folder heirarchy to be transcoded
* Make it impossible to collapse either side of the MainWindow splitter
* Add menu items for updating and doing a full rescan of Google Drive
* Increase Soundcloud cover image size
* Ability to pause Spotify tracks
* Add the ability to add or remove a Spotify track to a Spotify playlist
through context menu
* Add Spotify tracks to Spotify playlists by drag and drop
* Add ability to get a link to share Spotify playlists and songs
* Add ability to automatically set podcast as listened after sucesfully sending
it to a device
* Add ability to order podcasts by age
* Allow user to download multiple podcasts at the same time
* Add ability to cancel podcast downloads in progress
* Allow user to hide listened podcast episodes
* Huge improvement of the speed at startup
* Improve performance of mass rating changes
* Improve ripping performance
* Persistent cache for pixmaps. Huge improvement of the performance when
scrolling the library for example
* Add AppData file for Clementine (for GNOME and KDE Software Centers)
Bugfixes:
* Fix crash when click on a SoundCloud entry in internet tab
* Fix crash when marking podcast as listened
* Fix crash after pressing OK in the device properties window
* Fix stop after track which doesn't remove now playing
* Fix play bleeding into next track after auto stop
* Fix analyzer framerate when mouseover play scrubber
* Fix issues with buffers sent to analyzer
* Fix block analyzer framerate
* Fix dbz possibility with small buffers at end of track
* Fix dbz possibility in moodbar
* Fix oversized album cover art
* Fix Grooveshark SSL errors
* Clean cover art from /tmp
* Fix the rendering of the little numbers in the boxes on queued items in
the playlist
* Fix parsing of MusicBrainz data for discid
* Fix random artifacting on nyanalyzer on startup
* Fix podcasts length issues (which caused issues with seeking for example)
* Fix too small equalizer window size
* Fix labels which don't inherit system text colors in the edit tag dialog
* Fix the mess of the queue manager after playlist re-sort
* Fix for queue ordering issue in the playlist view when using c-d to
dequeue a track
* Fix detection of parent-relative paths in playlist saving
* Fix path seperators issue when reading playlists
* Fix m3u parser issue when an artist's name has a hyphen
* Fix bug with percents when fetch the Jamendo catalogue
* Fix a little dropout when transition to next track
* Fix broken RockRadio.com for premium users
* Fix Subsonic login with + characters in the password
* Fix accents issue in when save playlist in xspf format
* Fix issues with some songs length thanks to Taglib. People with Taglib
installed on their system will have to wait a new release of Taglib
* Fix moodbars not generating correctly
* Fix socket leak in moodbar
* Fix memory leak in tagreader
* Remove Ubuntu One support
Build system changes:
* Update to gstreamer 1.0
* Don't compile vreen with link-time optimizations
* Use the system's sha2 library if it's available
* (Windows) Add libgmp-10.dll which is required by libgiognutls.dll
* (Fedora) Don't depend on libplist or usbmuxd
Version 1.2.3:
Bugfixes:
* Fix compilation with GCC 4.9.

9
cmake/C++11Compat.cmake Normal file
View File

@ -0,0 +1,9 @@
# Hacky stuff to make C++11 features work with old compilers.
if (CMAKE_COMPILER_IS_GNUCC)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_LESS 4.7)
add_definitions(-Doverride=)
endif()
endif()

View File

@ -1,3 +1,3 @@
# Increment this whenever the user needs to download a new blob
# Remember to upload and sign the new version of the blob.
set(SPOTIFY_BLOB_VERSION 14)
set(SPOTIFY_BLOB_VERSION 15)

View File

@ -37,6 +37,7 @@
<file>icons/22x22/edit-redo.png</file>
<file>icons/22x22/edit-rename.png</file>
<file>icons/22x22/edit-undo.png</file>
<file>icons/22x22/enterprise.png</file>
<file>icons/22x22/folder-new.png</file>
<file>icons/22x22/folder.png</file>
<file>icons/22x22/folder-sound.png</file>
@ -48,8 +49,10 @@
<file>icons/22x22/go-up.png</file>
<file>icons/22x22/help-about.png</file>
<file>icons/22x22/help-hint.png</file>
<file>icons/22x22/hypnotoad.png</file>
<file>icons/22x22/input-keyboard.png</file>
<file>icons/22x22/ipodtouchicon.png</file>
<file>icons/22x22/kittens.png</file>
<file>icons/22x22/list-add.png</file>
<file>icons/22x22/list-remove.png</file>
<file>icons/22x22/mail-message.png</file>
@ -113,6 +116,7 @@
<file>icons/32x32/edit-redo.png</file>
<file>icons/32x32/edit-rename.png</file>
<file>icons/32x32/edit-undo.png</file>
<file>icons/32x32/enterprise.png</file>
<file>icons/32x32/folder-new.png</file>
<file>icons/32x32/folder.png</file>
<file>icons/32x32/folder-sound.png</file>
@ -124,8 +128,10 @@
<file>icons/32x32/go-up.png</file>
<file>icons/32x32/help-about.png</file>
<file>icons/32x32/help-hint.png</file>
<file>icons/32x32/hypnotoad.png</file>
<file>icons/32x32/input-keyboard.png</file>
<file>icons/32x32/ipodtouchicon.png</file>
<file>icons/32x32/kittens.png</file>
<file>icons/32x32/list-add.png</file>
<file>icons/32x32/list-remove.png</file>
<file>icons/32x32/mail-message.png</file>
@ -189,6 +195,7 @@
<file>icons/48x48/edit-redo.png</file>
<file>icons/48x48/edit-rename.png</file>
<file>icons/48x48/edit-undo.png</file>
<file>icons/48x48/enterprise.png</file>
<file>icons/48x48/folder-new.png</file>
<file>icons/48x48/folder.png</file>
<file>icons/48x48/folder-sound.png</file>
@ -200,8 +207,10 @@
<file>icons/48x48/go-up.png</file>
<file>icons/48x48/help-about.png</file>
<file>icons/48x48/help-hint.png</file>
<file>icons/48x48/hypnotoad.png</file>
<file>icons/48x48/input-keyboard.png</file>
<file>icons/48x48/ipodtouchicon.png</file>
<file>icons/48x48/kittens.png</file>
<file>icons/48x48/list-add.png</file>
<file>icons/48x48/list-remove.png</file>
<file>icons/48x48/mail-message.png</file>
@ -325,14 +334,13 @@
<file>providers/radiogfm.png</file>
<file>providers/rockradio.png</file>
<file>providers/skydrive.png</file>
<file>providers/skyfm.png</file>
<file>providers/somafm.png</file>
<file>providers/songkick.png</file>
<file>providers/soundcloud.png</file>
<file>providers/subsonic-32.png</file>
<file>providers/subsonic.png</file>
<file>providers/ubuntuone.png</file>
<file>providers/wikipedia.png</file>
<file>rainbowdash.png</file>
<file>sample.mood</file>
<file>schema/device-schema.sql</file>
<file>schema/jamendo.sql</file>
@ -376,6 +384,7 @@
<file>schema/schema-44.sql</file>
<file>schema/schema-45.sql</file>
<file>schema/schema-46.sql</file>
<file>schema/schema-47.sql</file>
<file>schema/schema-4.sql</file>
<file>schema/schema-5.sql</file>
<file>schema/schema-6.sql</file>
@ -414,5 +423,8 @@
<file>vk/deactivated.gif</file>
<file>providers/vk.png</file>
<file>vk/link.png</file>
<file>providers/seafile.png</file>
<file>icons/32x32/internet-services.png</file>
<file>providers/radiotunes.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -59,6 +59,13 @@
</extract>
<invalidIndicator value="Verifique se o nome do seu arquivo e sua"/>
</provider>
<provider name="lololyrics.com" title="" charset="utf-8" url="http://api.lololyrics.com/0.5/getLyric?artist={artist}&amp;track={title}">
<urlFormat replace="_@,;&amp;\/&quot;#" with="_"/>
<extract>
<item tag="&lt;response&gt;"/>
</extract>
<invalidIndicator value="ERROR"/>
</provider>
<provider name="loudson.gs" title="" charset="utf-8" url="http://www.loudson.gs/{a}/{artist}/{album}/{title}">
<urlFormat replace=" _@,;&amp;\/&quot;" with="-"/>
<urlFormat replace="." with=""/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

BIN
data/providers/seafile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

BIN
data/rainbowdash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

50
data/schema/schema-47.sql Normal file
View File

@ -0,0 +1,50 @@
CREATE TABLE seafile_songs(
title TEXT,
album TEXT,
artist TEXT,
albumartist TEXT,
composer TEXT,
track INTEGER,
disc INTEGER,
bpm REAL,
year INTEGER,
genre TEXT,
comment TEXT,
compilation INTEGER,
length INTEGER,
bitrate INTEGER,
samplerate INTEGER,
directory INTEGER NOT NULL,
filename TEXT NOT NULL,
mtime INTEGER NOT NULL,
ctime INTEGER NOT NULL,
filesize INTEGER NOT NULL,
sampler INTEGER NOT NULL DEFAULT 0,
art_automatic TEXT,
art_manual TEXT,
filetype INTEGER NOT NULL DEFAULT 0,
playcount INTEGER NOT NULL DEFAULT 0,
lastplayed INTEGER,
rating INTEGER,
forced_compilation_on INTEGER NOT NULL DEFAULT 0,
forced_compilation_off INTEGER NOT NULL DEFAULT 0,
effective_compilation NOT NULL DEFAULT 0,
skipcount INTEGER NOT NULL DEFAULT 0,
score INTEGER NOT NULL DEFAULT 0,
beginning INTEGER NOT NULL DEFAULT 0,
cue_path TEXT,
unavailable INTEGER DEFAULT 0,
effective_albumartist TEXT,
etag TEXT,
performer TEXT,
grouping TEXT
);
CREATE VIRTUAL TABLE seafile_songs_fts USING fts3 (
ftstitle, ftsalbum, ftsartist, ftsalbumartist, ftscomposer, ftsperformer, ftsgrouping, ftsgenre, ftscomment,
tokenize=unicode
);
UPDATE schema_version SET version=47;

13
debian/control vendored
View File

@ -13,14 +13,15 @@ Build-Depends: debhelper (>= 7),
libboost-serialization1.40-dev |
libboost-serialization1.42-dev |
libboost-serialization-dev,
libcdio-cdda1,
libglew1.5-dev |
libglew-dev,
libqt4-dev,
qt4-dev-tools,
libqt4-opengl-dev,
cmake,
libgstreamer0.10-dev,
libgstreamer-plugins-base0.10-dev,
libgstreamer1.0-dev,
libgstreamer-plugins-base1.0-dev,
libgpod-dev,
libimobiledevice-dev,
libplist-dev,
@ -43,10 +44,10 @@ Package: clementine
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends},
libsqlite3-0,
gstreamer0.10-plugins-base,
gstreamer0.10-plugins-good,
gstreamer0.10-alsa | gstreamer0.10-audiosink,
gstreamer0.10-plugins-ugly,
gstreamer1.0-plugins-base,
gstreamer1.0-plugins-good,
gstreamer1.0-plugins-ugly,
gstreamer1.0-pulseaudio,
libprojectm-data | projectm-data,
libqca2-plugin-ossl
Description: Modern music player and library organiser inspired by Amarok 1.4

4
dist/CMakeLists.txt vendored
View File

@ -60,6 +60,10 @@ if (NOT APPLE)
DESTINATION share/kde4/services
)
install(FILES clementine.appdata.xml
DESTINATION share/appdata
)
if(INSTALL_UBUNTU_ICONS)
foreach(icon clementine-panel.png clementine-panel-grey.png)
foreach(theme ubuntu-mono-dark ubuntu-mono-light)

3894
dist/cacert.pem vendored Normal file

File diff suppressed because it is too large Load Diff

35
dist/clementine.appdata.xml vendored Normal file
View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2014 David Sansome <me@davidsansome.com> -->
<application>
<id type="desktop">clementine.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<name>Clementine Music Player</name>
<summary>Plays music files and internet radio</summary>
<description>
<p>
Clementine is a multiplatform music player focusing on a fast and
easy-to-use interface for searching and playing your music.
</p>
<p>Summary of included features:</p>
<ul>
<li>Search and play your local music library</li>
<li>Listen to internet radio from Last.fm, SomaFM and Magnatune</li>
<li>Tabbed playlists, import and export M3U, XSPF, PLS and ASX</li>
<li>Visualisations from projectM</li>
<li>Transcode music into MP3, Ogg Vorbis, Ogg Speex, FLAC or AA</li>
<li>Edit tags on MP3 and OGG files, organise your music</li>
<li>Download missing album cover art from Last.fm</li>
<li>Native desktop notifications using libnotify</li>
<li>Supports MPRIS, or remote control using the command-line</li>
<li>Remote control using a Wii Remote, MPRIS or the command-line</li>
<li>Copy music to your iPod, iPhone, MTP or mass-storage USB player</li>
</ul>
</description>
<screenshots>
<screenshot type="default" width="1139" height="724">https://clementine-player.github.io/pages/images/screenshots/clementine-1.2-1.png</screenshot>
<screenshot width="1080" height="724">https://clementine-player.github.io/pages/images/screenshots/clementine-1.2-2.png</screenshot>
</screenshots>
<url type="homepage">https://www.clementine-player.org</url>
<updatecontact>me@davidsansome.com</updatecontact>
</application>

View File

@ -11,8 +11,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: desktop-file-utils liblastfm-devel taglib-devel gettext
BuildRequires: qt4-devel boost-devel gcc-c++ glew-devel libgpod-devel
BuildRequires: cmake gstreamer-devel gstreamer-plugins-base-devel
BuildRequires: libplist-devel usbmuxd-devel
BuildRequires: cmake gstreamer1-devel gstreamer1-plugins-base-devel
BuildRequires: libmtp-devel protobuf-devel protobuf-compiler libcdio-devel
BuildRequires: qjson-devel qca2-devel fftw-devel sparsehash-devel
BuildRequires: sqlite-devel pulseaudio-libs-devel
@ -20,18 +19,18 @@ BuildRequires: sqlite-devel pulseaudio-libs-devel
Requires: libgpod protobuf-lite libcdio qjson qca-ossl sqlite
# GStreamer codec dependencies
Requires: gstreamer-plugins-ugly
Requires: gstreamer1-plugins-ugly
%ifarch x86_64
Requires: gstreamer0.10(decoder-audio/x-vorbis)()(64bit)
Requires: gstreamer0.10(decoder-audio/x-flac)()(64bit)
Requires: gstreamer0.10(decoder-audio/x-speex)()(64bit)
Requires: gstreamer0.10(decoder-audio/x-wav)()(64bit)
Requires: gstreamer1(decoder-audio/x-vorbis)()(64bit)
Requires: gstreamer1(decoder-audio/x-flac)()(64bit)
Requires: gstreamer1(decoder-audio/x-speex)()(64bit)
Requires: gstreamer1(decoder-audio/x-wav)()(64bit)
%else
Requires: gstreamer0.10(decoder-audio/x-vorbis)
Requires: gstreamer0.10(decoder-audio/x-flac)
Requires: gstreamer0.10(decoder-audio/x-speex)
Requires: gstreamer0.10(decoder-audio/x-wav)
Requires: gstreamer1(decoder-audio/x-vorbis)
Requires: gstreamer1(decoder-audio/x-flac)
Requires: gstreamer1(decoder-audio/x-speex)
Requires: gstreamer1(decoder-audio/x-wav)
%endif
%description
@ -79,6 +78,7 @@ make clean
%doc
%{_bindir}/clementine
%{_bindir}/clementine-tagreader
%{_datadir}/appdata/clementine.appdata.xml
%{_datadir}/applications/clementine.desktop
%{_datadir}/clementine/projectm-presets
%{_datadir}/kde4/services/clementine-itms.protocol

157
dist/copyright.py vendored Executable file
View File

@ -0,0 +1,157 @@
#!/usr/bin/python
from subprocess import *
from sys import *
from os import rename, remove
from datetime import *
def pretty_years(s):
l = list(s)
l.sort()
start = None
prev = None
r = []
for x in l:
if prev is None:
start = x
prev = x
continue
if x == prev + 1:
prev = x
continue
if prev == start:
r.append("%i" % prev)
else:
r.append("%i-%i" % (start, prev))
start = x
prev = x
if not prev is None:
if prev == start:
r.append("%i" % prev)
else:
r.append("%i-%i" % (start, prev))
return ", ".join(r)
def order_by_year(a, b):
la = list(a[2])
la.sort()
lb = list(b[2])
lb.sort()
if la[0] < lb[0]:
return -1
elif la[0] > lb[0]:
return 1
else:
return 0
def gen_copyrights(f):
commits = []
data = {}
copyrights = []
for ln in Popen(["git", "blame", "--incremental", f], stdout=PIPE).stdout:
if ln.startswith("filename "):
if len(data) > 0:
commits.append(data)
data = {}
elif ln.startswith("author "):
data["author"] = ln[7:].strip()
elif ln.startswith("author-mail <"):
data["author-mail"] = ln[12:].strip()
elif ln.startswith("author-time "):
data["author-time"] = ln[11:].strip()
elif ln.startswith("author-tz "):
data["author-tz"] = ln[9:].strip()
with open(f,'r') as fi:
fil = fi.readlines()
for i in fil:
if -1 < i.find("Original Author"):
da = i.split(" ")
print f
copyrights.append(" Copyright %s, %s %s\n" % (da[3].strip(), da[1], da[2]))
by_author = {}
for c in commits:
try:
n = by_author[c["author"]]
except KeyError:
n = (c["author"], c["author-mail"], set())
by_author[c["author"]] = n
# FIXME: Handle time zones properly
year = datetime.fromtimestamp(int(c["author-time"])).year
n[2].add(year)
for an, a in list(by_author.iteritems()):
for bn, b in list(by_author.iteritems()):
if a is b:
continue
if a[1] == b[1]:
a[2].update(b[2])
if by_author.has_key(an) and by_author.has_key(bn):
del by_author[bn]
copyright = list(by_author.itervalues())
copyright.sort(order_by_year)
for name, mail, years in copyright:
copyrights.append(" Copyright %s, %s %s\n" % (pretty_years(years), name, mail))
return copyrights
def change_file(filename):
content=[]
out=[]
extended=0
ends=0
with open(filename, "r") as fi:
content=fi.readlines()
copyrights=gen_copyrights(filename)
if -1 == content[0].find("/* This file is part of Clementine."):
print("File {} have no Clementine copyright info".format(filename))
return 0
for i in content:
if i.find("*/") != -1:
ends = 1
if i.find("Copyright ") != -1:
if not extended:
out.extend(copyrights)
extended = 1
if not ends:
continue
else:
out.append(i)
with open(filename+'_tmp', "w") as fi:
fi.writelines(out)
rename(filename+'_tmp', filename)
if __name__ == "__main__":
for files in argv[1:]:
change_file(files)

2684
dist/cpplint.py vendored

File diff suppressed because it is too large Load Diff

10
dist/format.py vendored Normal file → Executable file
View File

@ -1,3 +1,4 @@
#!/usr/bin/env python
import argparse
import difflib
import os
@ -20,6 +21,9 @@ def main():
help='file extensions to reformat')
parser.add_argument('-i', dest='inplace', action='store_true',
help='edit files inplace instead of showing a diff')
parser.add_argument('--files', nargs='*', metavar='FIL',
default=[],
help='get files as arguments insted of git')
args = parser.parse_args()
try:
@ -35,8 +39,14 @@ def main():
if not changed_files:
print >> sys.stderr, 'No changes from %s' % args.ref
if not args.files and not changed_files:
print >> sys.stderr, "Use --files to select files for reformat"
return
if args.files:
changed_files = args.files
for filename in changed_files:
if not os.path.splitext(filename)[1][1:] in args.extension:
continue

16
dist/macdeploy.py vendored
View File

@ -43,10 +43,10 @@ GSTREAMER_PLUGINS=[
'libgstaudioresample.so',
'libgstautodetect.so',
'libgstcoreelements.so',
'libgstdecodebin2.so',
'libgstequalizer.so',
'libgstgdp.so',
'libgstosxaudio.so',
'libgstplayback.so',
'libgsttcp.so',
'libgsttypefindfunctions.so',
'libgstudp.so',
@ -55,19 +55,19 @@ GSTREAMER_PLUGINS=[
# Codecs
'libgstapetag.so',
'libgstasf.so',
'libgstaudioparsers.so',
'libgstfaac.so',
'libgstfaad.so',
'libgstffmpeg.so',
'libgstflac.so',
'libgstid3demux.so',
'libgstisomp4.so',
'libgstlame.so',
'libgstlibav.so',
'libgstmad.so',
'libgstmms.so',
'libgstmpegaudioparse.so',
'libgstmusepack.so',
# TODO: Bring back Musepack support.
'libgstogg.so',
'libgstopus.so',
'libgstqtdemux.so',
'libgstreplaygain.so',
'libgstspeex.so',
'libgsttaglib.so',
@ -90,10 +90,8 @@ GSTREAMER_PLUGINS=[
]
GSTREAMER_SEARCH_PATH=[
'/target/lib/gstreamer-0.10',
'/target/libexec/gstreamer-0.10',
'/sw/lib/gstreamer-0.10',
'/usr/local/lib/gstreamer-0.10',
'/target/lib/gstreamer-1.0',
'/target/libexec/gstreamer-1.0',
]
QT_PLUGINS = [

View File

@ -194,20 +194,45 @@ Section "Delete old files" oldfiles
Delete "$INSTDIR\libgnutls-26.dll"
Delete "$INSTDIR\libpng14-14.dll"
Delete "$INSTDIR\libtasn1-3.dll"
; 1.2.3 Move to gstreamer-1.0
Delete "$INSTDIR\avcodec-53.dll"
Delete "$INSTDIR\avformat-53.dll"
Delete "$INSTDIR\avutil-51.dll"
Delete "$INSTDIR\libcdio-14.dll"
Delete "$INSTDIR\libgstapp-0.10-0.dll"
Delete "$INSTDIR\libgstaudio-0.10-0.dll"
Delete "$INSTDIR\libgstbase-0.10-0.dll"
Delete "$INSTDIR\libgstcdda-0.10-0.dll"
Delete "$INSTDIR\libgstcontroller-0.10-0.dll"
Delete "$INSTDIR\libgstdataprotocol-0.10-0.dll"
Delete "$INSTDIR\libgstfft-0.10-0.dll"
Delete "$INSTDIR\libgstinterfaces-0.10-0.dll"
Delete "$INSTDIR\libgstnet-0.10-0.dll"
Delete "$INSTDIR\libgstnetbuffer-0.10-0.dll"
Delete "$INSTDIR\libgstpbutils-0.10-0.dll"
Delete "$INSTDIR\libgstreamer-0.10-0.dll"
Delete "$INSTDIR\libgstriff-0.10-0.dll"
Delete "$INSTDIR\libgstrtp-0.10-0.dll"
Delete "$INSTDIR\libgstrtsp-0.10-0.dll"
Delete "$INSTDIR\libgstsdp-0.10-0.dll"
Delete "$INSTDIR\libgsttag-0.10-0.dll"
Delete "$INSTDIR\libsoup-2.4-1.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstdecodebin2.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstffmpeg.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstmpegaudioparse.dll"
Delete "$INSTDIR\gstreamer-plugins\libgstqtdemux.dll"
SectionEnd
Section "Clementine" Clementine
SetOutPath "$INSTDIR"
File "avcodec-53.dll"
File "avformat-53.dll"
File "avutil-51.dll"
File "clementine.exe"
File "clementine-tagreader.exe"
File "clementine-spotifyblob.exe"
File "clementine.ico"
File "glew32.dll"
File "libcdio-14.dll"
File "libcdio-16.dll"
File "libeay32.dll"
File "libfaac.dll"
File "libfaad.dll"
@ -223,23 +248,20 @@ Section "Clementine" Clementine
File "libgnutls-28.dll"
File "libgobject-2.0-0.dll"
File "libgpg-error-0.dll"
File "libgstapp-0.10-0.dll"
File "libgstaudio-0.10-0.dll"
File "libgstbase-0.10-0.dll"
File "libgstcdda-0.10-0.dll"
File "libgstcontroller-0.10-0.dll"
File "libgstdataprotocol-0.10-0.dll"
File "libgstfft-0.10-0.dll"
File "libgstinterfaces-0.10-0.dll"
File "libgstnet-0.10-0.dll"
File "libgstnetbuffer-0.10-0.dll"
File "libgstpbutils-0.10-0.dll"
File "libgstreamer-0.10-0.dll"
File "libgstriff-0.10-0.dll"
File "libgstrtp-0.10-0.dll"
File "libgstrtsp-0.10-0.dll"
File "libgstsdp-0.10-0.dll"
File "libgsttag-0.10-0.dll"
File "libgstapp-1.0-0.dll"
File "libgstaudio-1.0-0.dll"
File "libgstbase-1.0-0.dll"
File "libgstcontroller-1.0-0.dll"
File "libgstfft-1.0-0.dll"
File "libgstnet-1.0-0.dll"
File "libgstpbutils-1.0-0.dll"
File "libgstreamer-1.0-0.dll"
File "libgstriff-1.0-0.dll"
File "libgstrtp-1.0-0.dll"
File "libgstrtsp-1.0-0.dll"
File "libgstsdp-1.0-0.dll"
File "libgsttag-1.0-0.dll"
File "libgstvideo-1.0-0.dll"
File "libgthread-2.0-0.dll"
File "libhogweed-2-4.dll"
File "libiconv-2.dll"
@ -257,7 +279,6 @@ Section "Clementine" Clementine
File "libplist.dll"
File "libprotobuf-8.dll"
File "libqjson.dll"
File "libsoup-2.4-1.dll"
File "libspeex-1.dll"
File "libspotify.dll"
File "libstdc++-6.dll"
@ -355,28 +376,28 @@ Section "Gstreamer plugins" gstreamer-plugins
File "/oname=libgstasf.dll" "gstreamer-plugins\libgstasf.dll"
File "/oname=libgstaudioconvert.dll" "gstreamer-plugins\libgstaudioconvert.dll"
File "/oname=libgstaudiofx.dll" "gstreamer-plugins\libgstaudiofx.dll"
File "/oname=libgstaudioparsers.dll" "gstreamer-plugins\libgstaudioparsers.dll"
File "/oname=libgstaudioresample.dll" "gstreamer-plugins\libgstaudioresample.dll"
File "/oname=libgstaudiotestsrc.dll" "gstreamer-plugins\libgstaudiotestsrc.dll"
File "/oname=libgstautodetect.dll" "gstreamer-plugins\libgstautodetect.dll"
File "/oname=libgstcdio.dll" "gstreamer-plugins\libgstcdio.dll"
File "/oname=libgstcoreelements.dll" "gstreamer-plugins\libgstcoreelements.dll"
File "/oname=libgstdecodebin2.dll" "gstreamer-plugins\libgstdecodebin2.dll"
File "/oname=libgstdirectsoundsink.dll" "gstreamer-plugins\libgstdirectsoundsink.dll"
File "/oname=libgstequalizer.dll" "gstreamer-plugins\libgstequalizer.dll"
File "/oname=libgstfaac.dll" "gstreamer-plugins\libgstfaac.dll"
File "/oname=libgstfaad.dll" "gstreamer-plugins\libgstfaad.dll"
File "/oname=libgstffmpeg.dll" "gstreamer-plugins\libgstffmpeg.dll"
File "/oname=libgstflac.dll" "gstreamer-plugins\libgstflac.dll"
File "/oname=libgstgdp.dll" "gstreamer-plugins\libgstgdp.dll"
File "/oname=libgstgio.dll" "gstreamer-plugins\libgstgio.dll"
File "/oname=libgsticydemux.dll" "gstreamer-plugins\libgsticydemux.dll"
File "/oname=libgstid3demux.dll" "gstreamer-plugins\libgstid3demux.dll"
File "/oname=libgstisomp4.dll" "gstreamer-plugins\libgstisomp4.dll"
File "/oname=libgstlame.dll" "gstreamer-plugins\libgstlame.dll"
File "/oname=libgstlibav.dll" "gstreamer-plugins\libgstlibav.dll"
File "/oname=libgstmad.dll" "gstreamer-plugins\libgstmad.dll"
File "/oname=libgstmms.dll" "gstreamer-plugins\libgstmms.dll"
File "/oname=libgstmpegaudioparse.dll" "gstreamer-plugins\libgstmpegaudioparse.dll"
File "/oname=libgstogg.dll" "gstreamer-plugins\libgstogg.dll"
File "/oname=libgstqtdemux.dll" "gstreamer-plugins\libgstqtdemux.dll"
File "/oname=libgstplayback.dll" "gstreamer-plugins\libgstplayback.dll"
File "/oname=libgstreplaygain.dll" "gstreamer-plugins\libgstreplaygain.dll"
File "/oname=libgstsouphttpsrc.dll" "gstreamer-plugins\libgstsouphttpsrc.dll"
File "/oname=libgstspectrum.dll" "gstreamer-plugins\libgstspectrum.dll"
@ -1023,7 +1044,7 @@ Section "Uninstall"
Delete "$INSTDIR\clementine-spotifyblob.exe"
Delete "$INSTDIR\glew32.dll"
Delete "$INSTDIR\intl.dll"
Delete "$INSTDIR\libcdio-14.dll"
Delete "$INSTDIR\libcdio-16.dll"
Delete "$INSTDIR\libeay32.dll"
Delete "$INSTDIR\libexpat-1.dll"
Delete "$INSTDIR\libfaac.dll"

View File

@ -100,17 +100,16 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
gst_app_src_set_callbacks(appsrc_, &callbacks, this, nullptr);
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
const int endianness = G_BIG_ENDIAN;
static const char* format = "S16BE";
#elif Q_BYTE_ORDER == Q_LITTLE_ENDIAN
const int endianness = G_LITTLE_ENDIAN;
static const char* format = "S16LE";
#endif
// Set caps
GstCaps* caps = gst_caps_new_simple(
"audio/x-raw-int", "endianness", G_TYPE_INT, endianness, "signed",
G_TYPE_BOOLEAN, TRUE, "width", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16,
"rate", G_TYPE_INT, sample_rate, "channels", G_TYPE_INT, channels,
nullptr);
"audio/x-raw", "format", G_TYPE_STRING, format, "rate", G_TYPE_INT,
sample_rate, "channels", G_TYPE_INT, channels, "layout", G_TYPE_STRING,
"interleaved", nullptr);
gst_app_src_set_caps(appsrc_, caps);
gst_caps_unref(caps);
@ -128,16 +127,18 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
void MediaPipeline::WriteData(const char* data, qint64 length) {
if (!is_initialised()) return;
GstBuffer* buffer = gst_buffer_new_and_alloc(length);
GstBuffer* buffer = gst_buffer_new_allocate(nullptr, length, nullptr);
GstMapInfo map_info;
gst_buffer_map(buffer, &map_info, GST_MAP_WRITE);
memcpy(GST_BUFFER_DATA(buffer), data, length);
memcpy(map_info.data, data, length);
GST_BUFFER_OFFSET(buffer) = offset_bytes_;
GST_BUFFER_TIMESTAMP(buffer) = offset_bytes_ * kNsecPerSec / byte_rate_;
gst_buffer_unmap(buffer, &map_info);
GST_BUFFER_PTS(buffer) = offset_bytes_ * kNsecPerSec / byte_rate_;
GST_BUFFER_DURATION(buffer) = length * kNsecPerSec / byte_rate_;
offset_bytes_ += length;
GST_BUFFER_OFFSET_END(buffer) = offset_bytes_;
gst_app_src_push_buffer(appsrc_, buffer);
}

View File

@ -21,6 +21,7 @@
#include "spotifyclient.h"
#include <algorithm>
#include <memory>
#include <QCoreApplication>
#include <QDir>
@ -30,6 +31,7 @@
#include "core/arraysize.h"
#include "core/logging.h"
#include "core/timeconstants.h"
#include "mediapipeline.h"
#include "spotifykey.h"
#include "spotifymessages.pb.h"
@ -279,7 +281,7 @@ void SpotifyClient::MessageArrived(const pb::spotify::Message& message) {
} else if (message.has_playback_request()) {
StartPlayback(message.playback_request());
} else if (message.has_seek_request()) {
Seek(message.seek_request().offset_bytes());
Seek(message.seek_request().offset_nsec());
} else if (message.has_search_request()) {
Search(message.search_request());
} else if (message.has_image_request()) {
@ -292,6 +294,12 @@ void SpotifyClient::MessageArrived(const pb::spotify::Message& message) {
SetPlaybackSettings(message.set_playback_settings_request());
} else if (message.has_browse_toplist_request()) {
BrowseToplist(message.browse_toplist_request());
} else if (message.has_pause_request()) {
SetPaused(message.pause_request());
} else if (message.has_add_tracks_to_playlist()) {
AddTracksToPlaylist(message.add_tracks_to_playlist());
} else if (message.has_remove_tracks_from_playlist()) {
RemoveTracksFromPlaylist(message.remove_tracks_from_playlist());
}
}
@ -364,6 +372,8 @@ void SpotifyClient::PlaylistContainerLoadedCallback(sp_playlistcontainer* pc,
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);
// Install callbacks on all the playlists
sp_playlist_add_callbacks(sp_session_starred_create(me->session_),
&me->get_playlists_callbacks_, me);
const int count = sp_playlistcontainer_num_playlists(pc);
for (int i = 0; i < count; ++i) {
sp_playlist* playlist = sp_playlistcontainer_playlist(pc, i);
@ -432,6 +442,9 @@ void SpotifyClient::SendPlaylistList() {
pb::spotify::Playlists::Playlist* msg = response->add_playlist();
msg->set_index(i);
msg->set_name(sp_playlist_name(playlist));
sp_user* playlist_owner = sp_playlist_owner(playlist);
msg->set_is_mine(sp_session_user(session_) == playlist_owner);
msg->set_owner(sp_user_display_name(playlist_owner));
sp_playlist_offline_status offline_status =
sp_playlist_get_offline_status(session_, playlist);
@ -443,6 +456,13 @@ void SpotifyClient::SendPlaylistList() {
} else if (offline_status == SP_PLAYLIST_OFFLINE_STATUS_WAITING) {
msg->set_download_progress(0);
}
msg->set_nb_tracks(sp_playlist_num_tracks(playlist));
// URI - Blugh
char uri[256];
sp_link* link = sp_link_create_from_playlist(playlist);
sp_link_as_string(link, uri, arraysize(uri));
sp_link_release(link);
msg->set_uri(uri);
}
SendMessage(message);
@ -587,6 +607,77 @@ void SpotifyClient::PlaylistStateChangedForGetPlaylists(sp_playlist* pl,
me->SendPlaylistList();
}
void SpotifyClient::AddTracksToPlaylist(
const pb::spotify::AddTracksToPlaylistRequest& req) {
// Get the playlist we want to update
sp_playlist* playlist =
GetPlaylist(req.playlist_type(), req.playlist_index());
if (!playlist) {
qLog(Error) << "Playlist " << req.playlist_type() << ","
<< req.playlist_index() << "not found";
return;
}
// Get the tracks we want to add
std::unique_ptr<sp_track* []> tracks_array(
new sp_track* [req.track_uri_size()]);
for (int i = 0; i < req.track_uri_size(); ++i) {
sp_link* track_link = sp_link_create_from_string(req.track_uri(i).c_str());
sp_track* track = sp_link_as_track(track_link);
sp_track_add_ref(track);
sp_link_release(track_link);
if (!track) {
qLog(Error) << "Track" << QString::fromStdString(req.track_uri(i))
<< "not found";
}
tracks_array[i] = track;
}
// Actually add the tracks to the playlist
if (sp_playlist_add_tracks(playlist, tracks_array.get(), req.track_uri_size(),
0 /* TODO: don't insert at a hardcoded position */,
session_) != SP_ERROR_OK) {
qLog(Error) << "Error when adding tracks!";
}
// Clean everything
for (int i = 0; i < req.track_uri_size(); ++i) {
sp_track_release(tracks_array[i]);
}
}
void SpotifyClient::RemoveTracksFromPlaylist(
const pb::spotify::RemoveTracksFromPlaylistRequest& req) {
// Get the playlist we want to update
sp_playlist* playlist =
GetPlaylist(req.playlist_type(), req.playlist_index());
if (!playlist) {
qLog(Error) << "Playlist " << req.playlist_type() << ","
<< req.playlist_index() << "not found";
return;
}
// Get the position of the tracks we want to remove
std::unique_ptr<int[]> tracks_indices_array(new int[req.track_index_size()]);
for (int i = 0; i < req.track_index_size(); ++i) {
tracks_indices_array[i] = req.track_index(i);
}
// WTF: sp_playlist_remove_tracks indexes start from the end for starred
// playlist, not from the beginning like other playlists: reverse them
if (req.playlist_type() == pb::spotify::Starred) {
int num_tracks = sp_playlist_num_tracks(playlist);
for (int i = 0; i < req.track_index_size(); i++) {
tracks_indices_array[i] = num_tracks - tracks_indices_array[i] - 1;
}
}
if (sp_playlist_remove_tracks(playlist, tracks_indices_array.get(),
req.track_index_size()) != SP_ERROR_OK) {
qLog(Error) << "Error when removing tracks!";
}
}
void SpotifyClient::ConvertTrack(sp_track* track, pb::spotify::Track* pb) {
sp_album* album = sp_track_album(track);
@ -836,7 +927,7 @@ void SpotifyClient::StartPlayback(const pb::spotify::PlaybackRequest& req) {
TryPlaybackAgain(pending_playback);
}
void SpotifyClient::Seek(qint64 offset_bytes) {
void SpotifyClient::Seek(qint64 offset_nsec) {
// TODO
qLog(Error) << "TODO seeking";
}
@ -1014,6 +1105,10 @@ void SpotifyClient::BrowseToplist(
pending_toplist_browses_[browse] = req;
}
void SpotifyClient::SetPaused(const pb::spotify::PauseRequest& req) {
sp_session_player_play(session_, !req.paused());
}
void SpotifyClient::ToplistBrowseComplete(sp_toplistbrowse* result,
void* userdata) {
SpotifyClient* me = reinterpret_cast<SpotifyClient*>(userdata);

View File

@ -122,12 +122,16 @@ class SpotifyClient : public AbstractMessageHandler<pb::spotify::Message> {
void Search(const pb::spotify::SearchRequest& req);
void LoadPlaylist(const pb::spotify::LoadPlaylistRequest& req);
void SyncPlaylist(const pb::spotify::SyncPlaylistRequest& req);
void AddTracksToPlaylist(const pb::spotify::AddTracksToPlaylistRequest& req);
void RemoveTracksFromPlaylist(
const pb::spotify::RemoveTracksFromPlaylistRequest& req);
void StartPlayback(const pb::spotify::PlaybackRequest& req);
void Seek(qint64 offset_bytes);
void Seek(qint64 offset_nsec);
void LoadImage(const QString& id_b64);
void BrowseAlbum(const QString& uri);
void BrowseToplist(const pb::spotify::BrowseToplistRequest& req);
void SetPlaybackSettings(const pb::spotify::PlaybackSettings& req);
void SetPaused(const pb::spotify::PauseRequest& req);
void SendPlaylistList();
@ -191,7 +195,7 @@ class SpotifyClient : public AbstractMessageHandler<pb::spotify::Message> {
QMap<sp_toplistbrowse*, pb::spotify::BrowseToplistRequest>
pending_toplist_browses_;
QMap<sp_search*, QList<sp_albumbrowse*> > pending_search_album_browses_;
QMap<sp_search*, QList<sp_albumbrowse*>> pending_search_album_browses_;
QMap<sp_albumbrowse*, sp_search*> pending_search_album_browse_responses_;
QScopedPointer<MediaPipeline> media_pipeline_;

View File

@ -23,6 +23,7 @@ enum MsgType {
STOP_AFTER = 17;
GET_LIBRARY = 18;
RATE_SONG = 19;
GLOBAL_SEARCH = 100;
// Messages send by both
DISCONNECT = 2;
@ -53,6 +54,8 @@ enum MsgType {
DOWNLOAD_QUEUE_EMPTY = 51;
LIBRARY_CHUNK = 52;
DOWNLOAD_TOTAL_SIZE = 53;
GLOBAL_SEARCH_RESULT = 54;
TRANSCODING_FILES = 55;
}
// Valid Engine states
@ -284,9 +287,25 @@ message ResponseDownloadTotalSize {
optional int32 file_count = 2;
}
message RequestGlobalSearch {
optional string query = 1;
}
message ResponseGlobalSearch {
optional int32 id = 1;
optional string query = 2;
optional string search_provider = 3;
repeated SongMetadata song_metadata = 4;
}
message ResponseTranscoderStatus {
optional int32 processed = 1;
optional int32 total = 2;
}
// The message itself
message Message {
optional int32 version = 1 [default=16];
optional int32 version = 1 [default=18];
optional MsgType type = 2 [default=UNKNOWN]; // What data is in the message?
optional RequestConnect request_connect = 21;
@ -301,6 +320,7 @@ message Message {
optional RequestClosePlaylist request_close_playlist = 29;
optional RequestDownloadSongs request_download_songs = 31;
optional RequestRateSong request_rate_song = 35;
optional RequestGlobalSearch request_global_search = 37;
optional Repeat repeat = 13;
optional Shuffle shuffle = 14;
@ -318,4 +338,6 @@ message Message {
optional ResponseSongOffer response_song_offer = 33;
optional ResponseLibraryChunk response_library_chunk = 34;
optional ResponseDownloadTotalSize response_download_total_size = 36;
optional ResponseGlobalSearch response_global_search = 38;
optional ResponseTranscoderStatus response_transcoder_status = 39;
}

View File

@ -46,9 +46,13 @@ message Playlists {
message Playlist {
required int32 index = 1;
required string name = 2;
required bool is_offline = 3;
required int32 nb_tracks = 3;
required bool is_mine = 4;
required string owner= 5;
required bool is_offline = 6;
required string uri = 7;
// Offline sync progress between 0-100.
optional int32 download_progress = 4;
optional int32 download_progress = 8;
}
repeated Playlist playlist = 1;
@ -170,7 +174,7 @@ message BrowseToplistResponse {
}
message SeekRequest {
optional int64 offset_bytes = 1;
optional int64 offset_nsec = 1;
}
enum Bitrate {
@ -184,7 +188,23 @@ message PlaybackSettings {
optional bool volume_normalisation = 2 [default = false];
}
// NEXT_ID: 21
message PauseRequest {
optional bool paused = 1 [default = false];
}
message AddTracksToPlaylistRequest {
required PlaylistType playlist_type = 1;
optional int64 playlist_index = 2; // Used if playlist_index == UserPlaylist
repeated string track_uri = 3;
}
message RemoveTracksFromPlaylistRequest {
required PlaylistType playlist_type = 1;
optional int64 playlist_index = 2; // Used if playlist_index == UserPlaylist
repeated int64 track_index = 3;
}
// NEXT_ID: 25
message Message {
// Not currently used
optional int32 id = 18;
@ -208,4 +228,8 @@ message Message {
optional PlaybackSettings set_playback_settings_request = 17;
optional BrowseToplistRequest browse_toplist_request = 19;
optional BrowseToplistResponse browse_toplist_response = 20;
optional PauseRequest pause_request = 21;
// ID 22 unused.
optional AddTracksToPlaylistRequest add_tracks_to_playlist = 23;
optional RemoveTracksFromPlaylistRequest remove_tracks_from_playlist = 24;
}

View File

@ -502,10 +502,9 @@ void TagReader::ParseOggTag(const TagLib::Ogg::FieldListMap& map,
100);
}
void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song)
const {
void TagReader::SetVorbisComments(
TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const {
vorbis_comments->addField("COMPOSER",
StdStringToTaglibString(song.composer()), true);
vorbis_comments->addField("PERFORMER",
@ -524,6 +523,9 @@ void TagReader::SetVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments,
vorbis_comments->addField(
"COMPILATION", StdStringToTaglibString(song.compilation() ? "1" : "0"),
true);
vorbis_comments->addField("ALBUM ARTIST",
StdStringToTaglibString(song.albumartist()), true);
}
void TagReader::SetFMPSStatisticsVorbisComments(
@ -540,7 +542,6 @@ void TagReader::SetFMPSStatisticsVorbisComments(
void TagReader::SetFMPSRatingVorbisComments(
TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const {
vorbis_comments->addField(
"FMPS_RATING", QStringToTaglibString(QString::number(song.rating())));
}
@ -723,6 +724,14 @@ bool TagReader::SaveSongRatingToFile(
if (filename.isNull()) return false;
qLog(Debug) << "Saving song rating tags to" << filename;
if (song.rating() < 0) {
// The FMPS spec says unrated == "tag not present". For us, no rating
// results in rating being -1, so don't write anything in that case.
// Actually, we should also remove tag set in this case, but in
// Clementine it is not possible to unset rating i.e. make a song "unrated".
qLog(Debug) << "Unrated: do nothing";
return true;
}
std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
@ -945,38 +954,38 @@ bool TagReader::ReadCloudFile(const QUrl& download_url, const QString& title,
pb::tagreader::SongMetadata* song) const {
qLog(Debug) << "Loading tags from" << title;
CloudStream* stream = new CloudStream(download_url, title, size,
authorisation_header, network_);
std::unique_ptr<CloudStream> stream(new CloudStream(
download_url, title, size, authorisation_header, network_));
stream->Precache();
std::unique_ptr<TagLib::File> tag;
if (mime_type == "audio/mpeg" && title.endsWith(".mp3")) {
tag.reset(new TagLib::MPEG::File(stream, // Takes ownership.
tag.reset(new TagLib::MPEG::File(stream.get(),
TagLib::ID3v2::FrameFactory::instance(),
TagLib::AudioProperties::Accurate));
} else if (mime_type == "audio/mp4" ||
(mime_type == "audio/mpeg" && title.endsWith(".m4a"))) {
tag.reset(
new TagLib::MP4::File(stream, true, TagLib::AudioProperties::Accurate));
tag.reset(new TagLib::MP4::File(stream.get(), true,
TagLib::AudioProperties::Accurate));
}
#ifdef TAGLIB_HAS_OPUS
else if ((mime_type == "application/opus" || mime_type == "audio/opus" ||
mime_type == "application/ogg" || mime_type == "audio/ogg") &&
title.endsWith(".opus")) {
tag.reset(new TagLib::Ogg::Opus::File(stream, true,
tag.reset(new TagLib::Ogg::Opus::File(stream.get(), true,
TagLib::AudioProperties::Accurate));
}
#endif
else if (mime_type == "application/ogg" || mime_type == "audio/ogg") {
tag.reset(new TagLib::Ogg::Vorbis::File(stream, true,
tag.reset(new TagLib::Ogg::Vorbis::File(stream.get(), true,
TagLib::AudioProperties::Accurate));
} else if (mime_type == "application/x-flac" || mime_type == "audio/flac" ||
mime_type == "audio/x-flac") {
tag.reset(new TagLib::FLAC::File(stream,
tag.reset(new TagLib::FLAC::File(stream.get(),
TagLib::ID3v2::FrameFactory::instance(),
true, TagLib::AudioProperties::Accurate));
} else if (mime_type == "audio/x-ms-wma") {
tag.reset(
new TagLib::ASF::File(stream, true, TagLib::AudioProperties::Accurate));
tag.reset(new TagLib::ASF::File(stream.get(), true,
TagLib::AudioProperties::Accurate));
} else {
qLog(Debug) << "Unknown mime type for tagging:" << mime_type;
return false;

View File

@ -1,31 +0,0 @@
From 0b62ebc38d1cc0202c6f57c4e096fa0b68a41baf Mon Sep 17 00:00:00 2001
From: David Sansome <me@davidsansome.com>
Date: Sun, 27 May 2012 17:00:32 +0100
Subject: [PATCH] Protect calls to fftwf_plan_dft_r2c_1d with a mutex
---
plugin/gstfftwspectrum.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/plugin/gstfftwspectrum.c b/plugin/gstfftwspectrum.c
index 147e606..f6e2427 100644
--- a/plugin/gstfftwspectrum.c
+++ b/plugin/gstfftwspectrum.c
@@ -302,10 +302,14 @@ alloc_fftw_data (GstFFTWSpectrum *conv)
* outputs are the hermetian conjugates). This should be optimal for
* implementing filters.
*/
+
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+ g_static_mutex_lock(&mutex);
conv->fftw_plan
= fftwf_plan_dft_r2c_1d(conv->size, conv->fftw_in,
(fftwf_complex *) conv->fftw_out,
conv->hi_q ? FFTW_MEASURE : FFTW_ESTIMATE);
+ g_static_mutex_unlock(&mutex);
}
--
1.7.5.4

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.6)
set(CMAKE_C_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS "-Woverloaded-virtual -Wall")
set(CMAKE_CXX_FLAGS "-Woverloaded-virtual -Wall --std=c++0x")
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
@ -11,9 +11,8 @@ include_directories(${GSTREAMER_INCLUDE_DIRS})
include_directories(${FFTW3_INCLUDE_DIR})
set(SOURCES
gstfftwspectrum.c
gstmoodbar.c
spectrum.c
gstfastspectrum.cpp
plugin.cpp
)
add_library(gstmoodbar STATIC
@ -24,6 +23,7 @@ target_link_libraries(gstmoodbar
${GOBJECT_LIBRARIES}
${GLIB_LIBRARIES}
${GSTREAMER_LIBRARIES}
${GSTREAMER_AUDIO_LIBRARIES}
${GSTREAMER_BASE_LIBRARIES}
${FFTW3_FFTW_LIBRARY}
)

View File

@ -0,0 +1,553 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2006,2011> Stefan Kost <ensonic@users.sf.net>
* <2007-2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <cstring>
#include <cmath>
#include <QMutex>
#include <QMutexLocker>
#include "gstfastspectrum.h"
GST_DEBUG_CATEGORY_STATIC (gst_fastspectrum_debug);
#define GST_CAT_DEFAULT gst_fastspectrum_debug
/* elementfactory information */
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
# define FORMATS "{ S16LE, S24LE, S32LE, F32LE, F64LE }"
#else
# define FORMATS "{ S16BE, S24BE, S32BE, F32BE, F64BE }"
#endif
#define ALLOWED_CAPS \
GST_AUDIO_CAPS_MAKE (FORMATS) ", " \
"layout = (string) interleaved, " \
"channels = 1"
/* Spectrum properties */
#define DEFAULT_INTERVAL (GST_SECOND / 10)
#define DEFAULT_BANDS 128
enum {
PROP_0,
PROP_INTERVAL,
PROP_BANDS
};
#define gst_fastspectrum_parent_class parent_class
G_DEFINE_TYPE (GstFastSpectrum, gst_fastspectrum, GST_TYPE_AUDIO_FILTER);
static void gst_fastspectrum_finalize (GObject * object);
static void gst_fastspectrum_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_fastspectrum_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_fastspectrum_start (GstBaseTransform * trans);
static gboolean gst_fastspectrum_stop (GstBaseTransform * trans);
static GstFlowReturn gst_fastspectrum_transform_ip (GstBaseTransform * trans,
GstBuffer * in);
static gboolean gst_fastspectrum_setup (GstAudioFilter * base,
const GstAudioInfo * info);
static void
gst_fastspectrum_class_init (GstFastSpectrumClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
GstAudioFilterClass *filter_class = GST_AUDIO_FILTER_CLASS (klass);
GstCaps *caps;
gobject_class->set_property = gst_fastspectrum_set_property;
gobject_class->get_property = gst_fastspectrum_get_property;
gobject_class->finalize = gst_fastspectrum_finalize;
trans_class->start = GST_DEBUG_FUNCPTR (gst_fastspectrum_start);
trans_class->stop = GST_DEBUG_FUNCPTR (gst_fastspectrum_stop);
trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_fastspectrum_transform_ip);
trans_class->passthrough_on_same_caps = TRUE;
filter_class->setup = GST_DEBUG_FUNCPTR (gst_fastspectrum_setup);
g_object_class_install_property (gobject_class, PROP_INTERVAL,
g_param_spec_uint64 ("interval", "Interval",
"Interval of time between message posts (in nanoseconds)",
1, G_MAXUINT64, DEFAULT_INTERVAL,
GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, PROP_BANDS,
g_param_spec_uint ("bands", "Bands", "Number of frequency bands",
0, G_MAXUINT, DEFAULT_BANDS,
GParamFlags(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
GST_DEBUG_CATEGORY_INIT (gst_fastspectrum_debug, "spectrum", 0,
"audio spectrum analyser element");
gst_element_class_set_static_metadata (element_class, "Spectrum analyzer",
"Filter/Analyzer/Audio",
"Run an FFT on the audio signal, output spectrum data",
"Erik Walthinsen <omega@cse.ogi.edu>, "
"Stefan Kost <ensonic@users.sf.net>, "
"Sebastian Dröge <sebastian.droege@collabora.co.uk>");
caps = gst_caps_from_string (ALLOWED_CAPS);
gst_audio_filter_class_add_pad_templates (filter_class, caps);
gst_caps_unref (caps);
klass->fftw_lock = new QMutex;
}
static void
gst_fastspectrum_init (GstFastSpectrum * spectrum)
{
spectrum->interval = DEFAULT_INTERVAL;
spectrum->bands = DEFAULT_BANDS;
spectrum->channel_data_initialised = false;
g_mutex_init (&spectrum->lock);
}
static void
gst_fastspectrum_alloc_channel_data (GstFastSpectrum * spectrum)
{
guint bands = spectrum->bands;
guint nfft = 2 * bands - 2;
spectrum->input_ring_buffer = new double[nfft];
spectrum->fft_input = reinterpret_cast<double*>(
fftw_malloc(sizeof(double) * nfft));
spectrum->fft_output =reinterpret_cast<fftw_complex*>(
fftw_malloc(sizeof(fftw_complex) * (nfft/2+1)));
spectrum->spect_magnitude = new double[bands]{};
GstFastSpectrumClass* klass = reinterpret_cast<GstFastSpectrumClass*>(
G_OBJECT_GET_CLASS(spectrum));
{
QMutexLocker l(klass->fftw_lock);
spectrum->plan = fftw_plan_dft_r2c_1d(
nfft,
spectrum->fft_input,
spectrum->fft_output,
FFTW_ESTIMATE);
}
spectrum->channel_data_initialised = true;
}
static void
gst_fastspectrum_free_channel_data (GstFastSpectrum * spectrum)
{
GstFastSpectrumClass* klass = reinterpret_cast<GstFastSpectrumClass*>(
G_OBJECT_GET_CLASS(spectrum));
if (spectrum->channel_data_initialised) {
{
QMutexLocker l(klass->fftw_lock);
fftw_destroy_plan(spectrum->plan);
}
fftw_free(spectrum->fft_input);
fftw_free(spectrum->fft_output);
delete[] spectrum->input_ring_buffer;
delete[] spectrum->spect_magnitude;
spectrum->channel_data_initialised = false;
}
}
static void
gst_fastspectrum_flush (GstFastSpectrum * spectrum)
{
spectrum->num_frames = 0;
spectrum->num_fft = 0;
spectrum->accumulated_error = 0;
}
static void
gst_fastspectrum_reset_state (GstFastSpectrum * spectrum)
{
GST_DEBUG_OBJECT (spectrum, "resetting state");
gst_fastspectrum_free_channel_data (spectrum);
gst_fastspectrum_flush (spectrum);
}
static void
gst_fastspectrum_finalize (GObject * object)
{
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (object);
gst_fastspectrum_reset_state (spectrum);
g_mutex_clear (&spectrum->lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_fastspectrum_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstFastSpectrum *filter = GST_FASTSPECTRUM (object);
switch (prop_id) {
case PROP_INTERVAL:{
guint64 interval = g_value_get_uint64 (value);
g_mutex_lock (&filter->lock);
if (filter->interval != interval) {
filter->interval = interval;
gst_fastspectrum_reset_state (filter);
}
g_mutex_unlock (&filter->lock);
break;
}
case PROP_BANDS:{
guint bands = g_value_get_uint (value);
g_mutex_lock (&filter->lock);
if (filter->bands != bands) {
filter->bands = bands;
gst_fastspectrum_reset_state (filter);
}
g_mutex_unlock (&filter->lock);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_fastspectrum_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstFastSpectrum *filter = GST_FASTSPECTRUM (object);
switch (prop_id) {
case PROP_INTERVAL:
g_value_set_uint64 (value, filter->interval);
break;
case PROP_BANDS:
g_value_set_uint (value, filter->bands);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_fastspectrum_start (GstBaseTransform * trans)
{
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (trans);
gst_fastspectrum_reset_state (spectrum);
return TRUE;
}
static gboolean
gst_fastspectrum_stop (GstBaseTransform * trans)
{
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (trans);
gst_fastspectrum_reset_state (spectrum);
return TRUE;
}
/* mixing data readers */
static void
input_data_mixed_float(const guint8* _in, double* out, guint len,
double max_value, guint op, guint nfft)
{
guint j, ip = 0;
gfloat *in = (gfloat *) _in;
for (j = 0; j < len; j++) {
out[op] = in[ip++];
op = (op + 1) % nfft;
}
}
static void
input_data_mixed_double (const guint8 * _in, double* out, guint len,
double max_value, guint op, guint nfft)
{
guint j, ip = 0;
gdouble *in = (gdouble *) _in;
for (j = 0; j < len; j++) {
out[op] = in[ip++];
op = (op + 1) % nfft;
}
}
static void
input_data_mixed_int32_max (const guint8 * _in, double* out, guint len,
double max_value, guint op, guint nfft)
{
guint j, ip = 0;
gint32 *in = (gint32 *) _in;
for (j = 0; j < len; j++) {
out[op] = in[ip++] / max_value;
op = (op + 1) % nfft;
}
}
static void
input_data_mixed_int24_max (const guint8 * _in, double* out, guint len,
double max_value, guint op, guint nfft)
{
guint j;
for (j = 0; j < len; j++) {
#if G_BYTE_ORDER == G_BIG_ENDIAN
gint32 value = GST_READ_UINT24_BE (_in);
#else
gint32 value = GST_READ_UINT24_LE (_in);
#endif
if (value & 0x00800000)
value |= 0xff000000;
out[op] = value / max_value;
op = (op + 1) % nfft;
_in += 3;
}
}
static void
input_data_mixed_int16_max (const guint8 * _in, double * out, guint len,
double max_value, guint op, guint nfft)
{
guint j, ip = 0;
gint16 *in = (gint16 *) _in;
for (j = 0; j < len; j++) {
out[op] = in[ip++] / max_value;
op = (op + 1) % nfft;
}
}
static gboolean
gst_fastspectrum_setup (GstAudioFilter * base, const GstAudioInfo * info)
{
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (base);
GstFastSpectrumInputData input_data = NULL;
g_mutex_lock (&spectrum->lock);
switch (GST_AUDIO_INFO_FORMAT (info)) {
case GST_AUDIO_FORMAT_S16:
input_data = input_data_mixed_int16_max;
break;
case GST_AUDIO_FORMAT_S24:
input_data = input_data_mixed_int24_max;
break;
case GST_AUDIO_FORMAT_S32:
input_data = input_data_mixed_int32_max;
break;
case GST_AUDIO_FORMAT_F32:
input_data = input_data_mixed_float;
break;
case GST_AUDIO_FORMAT_F64:
input_data = input_data_mixed_double;
break;
default:
g_assert_not_reached ();
break;
}
spectrum->input_data = input_data;
gst_fastspectrum_reset_state (spectrum);
g_mutex_unlock (&spectrum->lock);
return TRUE;
}
static void
gst_fastspectrum_run_fft (GstFastSpectrum * spectrum, guint input_pos)
{
guint i;
guint bands = spectrum->bands;
guint nfft = 2 * bands - 2;
for (i = 0; i < nfft; i++)
spectrum->fft_input[i] =
spectrum->input_ring_buffer[(input_pos + i) % nfft];
// Should be safe to execute the same plan multiple times in parallel.
fftw_execute(spectrum->plan);
gdouble val;
/* Calculate magnitude in db */
for (i = 0; i < bands; i++) {
val = spectrum->fft_output[i][0] * spectrum->fft_output[i][0];
val += spectrum->fft_output[i][1] * spectrum->fft_output[i][1];
val /= nfft * nfft;
spectrum->spect_magnitude[i] += val;
}
}
static GstFlowReturn
gst_fastspectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
{
GstFastSpectrum *spectrum = GST_FASTSPECTRUM (trans);
guint rate = GST_AUDIO_FILTER_RATE (spectrum);
guint bps = GST_AUDIO_FILTER_BPS (spectrum);
guint bpf = GST_AUDIO_FILTER_BPF (spectrum);
double max_value = (1UL << ((bps << 3) - 1)) - 1;
guint bands = spectrum->bands;
guint nfft = 2 * bands - 2;
guint input_pos;
GstMapInfo map;
const guint8 *data;
gsize size;
guint fft_todo, msg_todo, block_size;
gboolean have_full_interval;
GstFastSpectrumInputData input_data;
g_mutex_lock (&spectrum->lock);
gst_buffer_map (buffer, &map, GST_MAP_READ);
data = map.data;
size = map.size;
GST_LOG_OBJECT (spectrum, "input size: %" G_GSIZE_FORMAT " bytes", size);
if (GST_BUFFER_IS_DISCONT (buffer)) {
GST_DEBUG_OBJECT (spectrum, "Discontinuity detected -- flushing");
gst_fastspectrum_flush (spectrum);
}
/* If we don't have a FFT context yet (or it was reset due to parameter
* changes) get one and allocate memory for everything
*/
if (!spectrum->channel_data_initialised) {
GST_DEBUG_OBJECT (spectrum, "allocating for bands %u", bands);
gst_fastspectrum_alloc_channel_data (spectrum);
/* number of sample frames we process before posting a message
* interval is in ns */
spectrum->frames_per_interval =
gst_util_uint64_scale (spectrum->interval, rate, GST_SECOND);
spectrum->frames_todo = spectrum->frames_per_interval;
/* rounding error for frames_per_interval in ns,
* aggregated it in accumulated_error */
spectrum->error_per_interval = (spectrum->interval * rate) % GST_SECOND;
if (spectrum->frames_per_interval == 0)
spectrum->frames_per_interval = 1;
GST_INFO_OBJECT (spectrum, "interval %" GST_TIME_FORMAT ", fpi %"
G_GUINT64_FORMAT ", error %" GST_TIME_FORMAT,
GST_TIME_ARGS (spectrum->interval), spectrum->frames_per_interval,
GST_TIME_ARGS (spectrum->error_per_interval));
spectrum->input_pos = 0;
gst_fastspectrum_flush (spectrum);
}
if (spectrum->num_frames == 0)
spectrum->message_ts = GST_BUFFER_TIMESTAMP (buffer);
input_pos = spectrum->input_pos;
input_data = spectrum->input_data;
while (size >= bpf) {
/* run input_data for a chunk of data */
fft_todo = nfft - (spectrum->num_frames % nfft);
msg_todo = spectrum->frames_todo - spectrum->num_frames;
GST_LOG_OBJECT (spectrum,
"message frames todo: %u, fft frames todo: %u, input frames %"
G_GSIZE_FORMAT, msg_todo, fft_todo, (size / bpf));
block_size = msg_todo;
if (block_size > (size / bpf))
block_size = (size / bpf);
if (block_size > fft_todo)
block_size = fft_todo;
/* Move the current frames into our ringbuffers */
input_data(data, spectrum->input_ring_buffer, block_size, max_value, input_pos, nfft);
data += block_size * bpf;
size -= block_size * bpf;
input_pos = (input_pos + block_size) % nfft;
spectrum->num_frames += block_size;
have_full_interval = (spectrum->num_frames == spectrum->frames_todo);
GST_LOG_OBJECT (spectrum,
"size: %" G_GSIZE_FORMAT ", do-fft = %d, do-message = %d", size,
(spectrum->num_frames % nfft == 0), have_full_interval);
/* If we have enough frames for an FFT or we have all frames required for
* the interval and we haven't run a FFT, then run an FFT */
if ((spectrum->num_frames % nfft == 0) ||
(have_full_interval && !spectrum->num_fft)) {
gst_fastspectrum_run_fft (spectrum, input_pos);
spectrum->num_fft++;
}
/* Do we have the FFTs for one interval? */
if (have_full_interval) {
GST_DEBUG_OBJECT (spectrum, "nfft: %u frames: %" G_GUINT64_FORMAT
" fpi: %" G_GUINT64_FORMAT " error: %" GST_TIME_FORMAT, nfft,
spectrum->num_frames, spectrum->frames_per_interval,
GST_TIME_ARGS (spectrum->accumulated_error));
spectrum->frames_todo = spectrum->frames_per_interval;
if (spectrum->accumulated_error >= GST_SECOND) {
spectrum->accumulated_error -= GST_SECOND;
spectrum->frames_todo++;
}
spectrum->accumulated_error += spectrum->error_per_interval;
if (spectrum->output_callback) {
// Calculate average
for (guint i = 0; i < spectrum->bands; i++) {
spectrum->spect_magnitude[i] /= spectrum->num_fft;
}
spectrum->output_callback(spectrum->spect_magnitude, spectrum->bands);
// Reset spectrum accumulators
memset(spectrum->spect_magnitude, 0, spectrum->bands * sizeof(double));
}
if (GST_CLOCK_TIME_IS_VALID (spectrum->message_ts))
spectrum->message_ts +=
gst_util_uint64_scale (spectrum->num_frames, GST_SECOND, rate);
spectrum->num_frames = 0;
spectrum->num_fft = 0;
}
}
spectrum->input_pos = input_pos;
gst_buffer_unmap (buffer, &map);
g_mutex_unlock (&spectrum->lock);
g_assert (size == 0);
return GST_FLOW_OK;
}

View File

@ -0,0 +1,98 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// Adapted from gstspectrum for Clementine with the following changes:
// - Uses fftw instead of kiss fft (2x faster).
// - Hardcoded to 1 channel (use an audioconvert element to do the work
// instead, simplifies this code a lot).
// - Send output via a callback instead of GST messages (less overhead).
// - Removed all properties except interval and band.
#ifndef GST_MOODBAR_FASTSPECTRUM_H_
#define GST_MOODBAR_FASTSPECTRUM_H_
#include <functional>
#include <gst/gst.h>
#include <gst/audio/gstaudiofilter.h>
#include <fftw3.h>
G_BEGIN_DECLS
#define GST_TYPE_FASTSPECTRUM (gst_fastspectrum_get_type())
#define GST_FASTSPECTRUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FASTSPECTRUM,GstFastSpectrum))
#define GST_IS_FASTSPECTRUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FASTSPECTRUM))
#define GST_FASTSPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_FASTSPECTRUM,GstFastSpectrumClass))
#define GST_IS_FASTSPECTRUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_FASTSPECTRUM))
class QMutex;
typedef void (*GstFastSpectrumInputData)(const guint8* in, double* out,
guint len, double max_value, guint op, guint nfft);
typedef std::function<void(double* magnitudes, int size)> OutputCallback;
struct GstFastSpectrum {
GstAudioFilter parent;
/* properties */
guint64 interval; /* how many nanoseconds between emits */
guint64 frames_per_interval; /* how many frames per interval */
guint64 frames_todo;
guint bands; /* number of spectrum bands */
gboolean multi_channel; /* send separate channel results */
guint64 num_frames; /* frame count (1 sample per channel)
* since last emit */
guint64 num_fft; /* number of FFTs since last emit */
GstClockTime message_ts; /* starttime for next message */
/* <private> */
bool channel_data_initialised;
double* input_ring_buffer;
double* fft_input;
fftw_complex* fft_output;
double* spect_magnitude;
fftw_plan plan;
guint input_pos;
guint64 error_per_interval;
guint64 accumulated_error;
GMutex lock;
GstFastSpectrumInputData input_data;
OutputCallback output_callback;
};
struct GstFastSpectrumClass {
GstAudioFilterClass parent_class;
// Static lock for creating & destroying FFTW plans.
QMutex* fftw_lock;
};
GType gst_fastspectrum_get_type (void);
G_END_DECLS
#endif // GST_MOODBAR_FASTSPECTRUM_H_

View File

@ -1,638 +0,0 @@
/* GStreamer FFTW-based signal-to-spectrum converter
* Copyright (C) 2006 Joseph Rabinoff <bobqwatson@yahoo.com>
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* SECTION:element-fftwspectrum
*
* <refsect2>
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch audiotestsrc ! audioconvert ! fftwspectrum ! fftwunspectrum ! audioconvert ! alsasink
* </programlisting>
* </para>
* </refsect2>
*/
/* This is a simple plugin to take an audio signal and return its
* Fourier transform, using fftw3. It takes a specified number N of
* samples and returns the first N/2+1 (complex) Fourier transform
* values (the other half of the values being the complex conjugates
* of the first). The modulus of these values correspond to the
* strength of the signal in their various bands, and the phase gives
* information about the phase of the signal. The step by which the
* transform increments is also variable, so it can return redundant
* data (to reduce artifacts when converting back into a signal).
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include <fftw3.h>
#include <string.h>
#include <math.h>
#include "gstfftwspectrum.h"
#include "spectrum.h"
GST_DEBUG_CATEGORY (gst_fftwspectrum_debug);
#define GST_CAT_DEFAULT gst_fftwspectrum_debug
/* Filter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
/* The size and step arguments are actually only default values
* used to fixate the size and step properties of the source cap.
*/
enum
{
ARG_0,
ARG_DEF_SIZE,
ARG_DEF_STEP,
ARG_HIQUALITY
};
#define DEF_SIZE_DEFAULT 1024
#define DEF_STEP_DEFAULT 512
#define HIQUALITY_DEFAULT TRUE
static GstStaticPadTemplate sink_factory
= GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
( SPECTRUM_SIGNAL_CAPS )
);
/* See spectrum.h for a definition of the frequency caps */
static GstStaticPadTemplate src_factory
= GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
( SPECTRUM_FREQ_CAPS )
);
GST_BOILERPLATE (GstFFTWSpectrum, gst_fftwspectrum, GstElement,
GST_TYPE_ELEMENT);
static void gst_fftwspectrum_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_fftwspectrum_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static gboolean gst_fftwspectrum_set_sink_caps (GstPad *pad, GstCaps *caps);
static gboolean gst_fftwspectrum_set_src_caps (GstPad *pad, GstCaps *caps);
static void gst_fftwspectrum_fixatecaps (GstPad *pad, GstCaps *caps);
static GstCaps *gst_fftwspectrum_getcaps (GstPad *pad);
static GstFlowReturn gst_fftwspectrum_chain (GstPad *pad, GstBuffer *buf);
static GstStateChangeReturn gst_fftwspectrum_change_state (GstElement *element,
GstStateChange transition);
#define OUTPUT_SIZE(conv) (((conv)->size/2+1)*sizeof(fftw_complex))
/***************************************************************/
/* GObject boilerplate stuff */
/***************************************************************/
static void
gst_fftwspectrum_base_init (gpointer gclass)
{
static GstElementDetails element_details =
{
"FFTW-based Fourier transform",
"Filter/Converter/Spectrum",
"Convert a raw audio stream into a frequency spectrum",
"Joe Rabinoff <bobqwatson@yahoo.com>"
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details (element_class, &element_details);
}
/* initialize the plugin's class */
static void
gst_fftwspectrum_class_init (GstFFTWSpectrumClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = gst_fftwspectrum_set_property;
gobject_class->get_property = gst_fftwspectrum_get_property;
g_object_class_install_property (gobject_class, ARG_DEF_SIZE,
g_param_spec_int ("def-size", "Default Size",
"Apply a Fourier transform to this many samples at a time (default value)",
1, G_MAXINT32, DEF_SIZE_DEFAULT, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_DEF_STEP,
g_param_spec_int ("def-step", "Default Step",
"Advance the stream this many samples each time (default value)",
1, G_MAXINT32, DEF_STEP_DEFAULT, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_HIQUALITY,
g_param_spec_boolean ("hiquality", "High Quality",
"Use a more time-consuming, higher quality algorithm chooser",
HIQUALITY_DEFAULT, G_PARAM_READWRITE));
gstelement_class->change_state
= GST_DEBUG_FUNCPTR (gst_fftwspectrum_change_state);
}
/* initialize the new element
* instantiate pads and add them to element
* set functions
* initialize structure
*/
static void
gst_fftwspectrum_init (GstFFTWSpectrum * conv,
GstFFTWSpectrumClass * gclass)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (conv);
conv->sinkpad =
gst_pad_new_from_template
(gst_element_class_get_pad_template (klass, "sink"), "sink");
gst_pad_set_setcaps_function (conv->sinkpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_set_sink_caps));
gst_pad_set_getcaps_function (conv->sinkpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_getcaps));
gst_pad_set_chain_function (conv->sinkpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_chain));
conv->srcpad =
gst_pad_new_from_template
(gst_element_class_get_pad_template (klass, "src"), "src");
gst_pad_set_setcaps_function (conv->srcpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_set_src_caps));
gst_pad_set_getcaps_function (conv->srcpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_getcaps));
gst_pad_set_fixatecaps_function (conv->srcpad,
GST_DEBUG_FUNCPTR (gst_fftwspectrum_fixatecaps));
gst_element_add_pad (GST_ELEMENT (conv), conv->sinkpad);
gst_element_add_pad (GST_ELEMENT (conv), conv->srcpad);
/* These are set once the (source) capabilities are determined */
conv->rate = 0;
conv->size = 0;
conv->step = 0;
/* These are set when we change to READY */
conv->fftw_in = NULL;
conv->fftw_out = NULL;
conv->fftw_plan = NULL;
/* These are set when we start receiving data */
conv->samples = NULL;
conv->numsamples = 0;
conv->timestamp = 0;
conv->offset = 0;
/* Properties */
conv->def_size = DEF_SIZE_DEFAULT;
conv->def_step = DEF_STEP_DEFAULT;
conv->hi_q = HIQUALITY_DEFAULT;
}
static void
gst_fftwspectrum_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstFFTWSpectrum *conv = GST_FFTWSPECTRUM (object);
switch (prop_id)
{
case ARG_DEF_SIZE:
conv->def_size = g_value_get_int (value);
break;
case ARG_DEF_STEP:
conv->def_step = g_value_get_int (value);
break;
case ARG_HIQUALITY:
conv->hi_q = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_fftwspectrum_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstFFTWSpectrum *conv = GST_FFTWSPECTRUM (object);
switch (prop_id)
{
case ARG_DEF_SIZE:
g_value_set_int (value, conv->def_size);
break;
case ARG_DEF_STEP:
g_value_set_int (value, conv->def_step);
break;
case ARG_HIQUALITY:
g_value_set_boolean (value, conv->hi_q);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* Allocate and deallocate fftw state data */
static void
free_fftw_data (GstFFTWSpectrum *conv)
{
if(conv->fftw_plan != NULL)
fftw_destroy_plan (conv->fftw_plan);
if(conv->fftw_in != NULL)
fftw_free (conv->fftw_in);
if(conv->fftw_out != NULL)
fftw_free (conv->fftw_out);
conv->fftw_in = NULL;
conv->fftw_out = NULL;
conv->fftw_plan = NULL;
}
static void
alloc_fftw_data (GstFFTWSpectrum *conv)
{
free_fftw_data (conv);
GST_DEBUG ("Allocating data for size = %d and step = %d",
conv->size, conv->step);
conv->fftw_in = (double *) fftw_malloc (sizeof(double) * conv->size);
conv->fftw_out = (double *) fftw_malloc (OUTPUT_SIZE (conv));
/* We use the simplest real-to-complex algorithm, which takes n real
* inputs and returns floor(n/2) + 1 complex outputs (the other n/2
* outputs are the hermetian conjugates). This should be optimal for
* implementing filters.
*/
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
g_static_mutex_lock(&mutex);
conv->fftw_plan
= fftw_plan_dft_r2c_1d(conv->size, conv->fftw_in,
(fftw_complex *) conv->fftw_out,
conv->hi_q ? FFTW_MEASURE : FFTW_ESTIMATE);
g_static_mutex_unlock(&mutex);
}
/***************************************************************/
/* Capabilities negotiation */
/***************************************************************/
/* The input and output capabilities are only related by the "rate"
* parameter, which is propagated so that an audio signal can be
* reconstructed eventually. This module does no rate conversion.
*
* The way I understand it, there are two times when caps negotiation
* takes place: (1) when a sink pad receives either its first buffer,
* or a buffer with a new caps type, and (2) when a source pad request
* a buffer from something downstream, and the returned allocated
* buffer has different caps from the ones already negotiated. In the
* first case, _set_sink_caps is called, and in the second, _set_src_caps
* is called.
* When (1) occurs, we remember the rate (the only variable parameter
* in the source) and set the source caps. Then _set_src_caps is called.
* In _set_src_caps, we check that the rate hasn't changed, and figure out
* or remember appropriate size and step attributes. If _set_src_caps is
* called from _set_sink_caps, this completes our setting up our internal
* configuration; if it is called from (2), we reconfigure just the source
* part of the internal configuration.
*/
static gboolean
gst_fftwspectrum_set_sink_caps (GstPad * pad, GstCaps * caps)
{
GstFFTWSpectrum *conv;
GstCaps *srccaps, *newsrccaps;
GstStructure *newstruct;
gint rate;
gboolean res;
conv = GST_FFTWSPECTRUM (gst_pad_get_parent (pad));
srccaps = gst_pad_get_allowed_caps (conv->srcpad);
newsrccaps = gst_caps_copy_nth (srccaps, 0);
gst_caps_unref (srccaps);
newstruct = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (newstruct, "rate", &rate))
{
gst_caps_unref (newsrccaps);
gst_object_unref (conv);
return FALSE;
}
/* Fixate the source caps with the given rate */
gst_caps_set_simple (newsrccaps, "rate", G_TYPE_INT, rate, NULL);
gst_pad_fixate_caps (conv->srcpad, newsrccaps);
conv->rate = rate;
res = gst_pad_set_caps (conv->srcpad, newsrccaps);
if (!res)
conv->rate = 0;
gst_caps_unref (newsrccaps);
gst_object_unref (conv);
return res;
}
static gboolean
gst_fftwspectrum_set_src_caps (GstPad * pad, GstCaps * caps)
{
GstFFTWSpectrum *conv;
gboolean res = FALSE;
GstStructure *newstruct;
gint rate;
conv = GST_FFTWSPECTRUM (gst_pad_get_parent (pad));
newstruct = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (newstruct, "rate", &rate))
goto out;
/* Assume caps negotiation has already taken place */
if (rate == conv->rate)
{
gint size, step;
if (!gst_structure_get_int (newstruct, "size", &size))
goto out;
if (!gst_structure_get_int (newstruct, "step", &step))
goto out;
if (conv->size != size || conv->step != step)
{
conv->size = size;
conv->step = step;
/* Re-allocate the fftw data */
if (GST_STATE (GST_ELEMENT (conv)) >= GST_STATE_READY)
alloc_fftw_data (conv);
}
res = TRUE;
}
out:
gst_object_unref (conv);
return res;
}
/* The only thing that can constrain the caps is the rate. */
static GstCaps *
gst_fftwspectrum_getcaps (GstPad *pad)
{
GstFFTWSpectrum *conv;
GstCaps *tmplcaps;
conv = GST_FFTWSPECTRUM (gst_pad_get_parent (pad));
tmplcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
if(conv->rate != 0)
{
/* Assumes the template caps are simple */
gst_caps_set_simple (tmplcaps, "rate", G_TYPE_INT, conv->rate, NULL);
}
gst_object_unref (conv);
return tmplcaps;
}
/* This is called when the source pad needs to choose its capabilities
* when it has a choice and nobody's forcing its hand. In this case
* we take our hint from the def_size and def_step properties.
*/
static void
gst_fftwspectrum_fixatecaps (GstPad *pad, GstCaps *caps)
{
GstFFTWSpectrum *conv;
GstStructure *s;
const GValue *val;
conv = GST_FFTWSPECTRUM (gst_pad_get_parent (pad));
s = gst_caps_get_structure (caps, 0);
val = gst_structure_get_value (s, "size");
if (val == NULL)
gst_caps_set_simple (caps, "size", G_TYPE_INT, conv->def_size, NULL);
else if (G_VALUE_TYPE (val) == GST_TYPE_INT_RANGE)
{
gint sizemin, sizemax;
sizemin = gst_value_get_int_range_min (val);
sizemax = gst_value_get_int_range_max (val);
gst_caps_set_simple (caps, "size", G_TYPE_INT,
CLAMP (conv->def_size, sizemin, sizemax), NULL);
}
/* else it should be already fixed */
val = gst_structure_get_value (s, "step");
if (val == NULL)
gst_caps_set_simple (caps, "step", G_TYPE_INT, conv->def_step, NULL);
else if (G_VALUE_TYPE (val) == GST_TYPE_INT_RANGE)
{
gint stepmin, stepmax;
stepmin = gst_value_get_int_range_min (val);
stepmax = gst_value_get_int_range_max (val);
gst_caps_set_simple (caps, "step", G_TYPE_INT,
CLAMP (conv->def_step, stepmin, stepmax), NULL);
}
/* else it should be already fixed */
/* Assume rate is already fixed (if not it'll be fixed by default) */
gst_object_unref (conv);
}
/***************************************************************/
/* Actual conversion */
/***************************************************************/
static GstStateChangeReturn
gst_fftwspectrum_change_state (GstElement * element,
GstStateChange transition)
{
GstFFTWSpectrum *conv = GST_FFTWSPECTRUM (element);
GstStateChangeReturn res;
switch (transition)
{
case GST_STATE_CHANGE_NULL_TO_READY:
alloc_fftw_data (conv);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
conv->samples = (gdouble *) g_malloc (sizeof(gdouble));
conv->numsamples = 0;
conv->timestamp = 0;
conv->offset = 0;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
res = parent_class->change_state (element, transition);
switch (transition)
{
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
g_free(conv->samples);
conv->samples = NULL;
conv->numsamples = 0;
conv->timestamp = 0;
conv->offset = 0;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
free_fftw_data (conv);
break;
default:
break;
}
return res;
}
/* Adds the samples contained in buf to the end of conv->samples,
* updating conv->numsamples.
*/
static void
push_samples (GstFFTWSpectrum *conv, GstBuffer *buf)
{
gint newsamples = GST_BUFFER_SIZE (buf) / sizeof (gdouble);
gint oldsamples = conv->numsamples;
conv->numsamples += newsamples;
conv->samples = g_realloc (conv->samples, conv->numsamples * sizeof (gdouble));
memcpy (&conv->samples[oldsamples], GST_BUFFER_DATA (buf),
newsamples * sizeof (gdouble));
/* GST_LOG ("Added %d samples", newsamples); */
}
/* This basically does the opposite of push_samples, but takes samples
* off the front.
*/
static void
shift_samples (GstFFTWSpectrum *conv, gint toshift)
{
gdouble *oldsamples = conv->samples;
conv->numsamples -= toshift;
conv->samples = g_malloc (MAX (conv->numsamples, 1) * sizeof (double));
memcpy (conv->samples, &oldsamples[toshift],
conv->numsamples * sizeof (gdouble));
g_free (oldsamples);
/* Fix the timestamp and offset */
conv->timestamp
+= gst_util_uint64_scale_int (GST_SECOND, toshift, conv->rate);
conv->offset += toshift;
/* GST_LOG ("Disposed of %d samples (time: %" GST_TIME_FORMAT " offset: %llu)",
toshift, GST_TIME_ARGS(conv->timestamp), conv->offset); */
}
/* This function queues samples until there are at least
* max (conv->size, conv->step) samples to process. We
* then process samples in chunks of conv->size and increment
* by conv->step.
*/
static GstFlowReturn
gst_fftwspectrum_chain (GstPad * pad, GstBuffer * buf)
{
GstFFTWSpectrum *conv;
GstBuffer *outbuf;
GstFlowReturn res = GST_FLOW_OK;
conv = GST_FFTWSPECTRUM (gst_pad_get_parent (pad));
push_samples (conv, buf);
gst_buffer_unref (buf);
while (conv->numsamples >= MAX (conv->size, conv->step))
{
res = gst_pad_alloc_buffer_and_set_caps
(conv->srcpad, conv->offset, OUTPUT_SIZE (conv),
GST_PAD_CAPS(conv->srcpad), &outbuf);
if (res != GST_FLOW_OK)
break;
GST_BUFFER_SIZE (outbuf) = OUTPUT_SIZE (conv);
GST_BUFFER_OFFSET (outbuf) = conv->offset;
GST_BUFFER_OFFSET_END (outbuf) = conv->offset + conv->step;
GST_BUFFER_TIMESTAMP (outbuf) = conv->timestamp;
GST_BUFFER_DURATION (outbuf)
= gst_util_uint64_scale_int (GST_SECOND, conv->step, conv->rate);
/* Do the Fourier transform */
memcpy (conv->fftw_in, conv->samples, conv->size * sizeof (double));
fftw_execute (conv->fftw_plan);
{ /* Normalize */
gint i;
gfloat root = sqrtf (conv->size);
for (i = 0; i < 2*(conv->size/2+1); ++i)
conv->fftw_out[i] /= root;
}
memcpy (GST_BUFFER_DATA (outbuf), conv->fftw_out, OUTPUT_SIZE (conv));
res = gst_pad_push (conv->srcpad, outbuf);
shift_samples (conv, conv->step);
if (res != GST_FLOW_OK)
break;
}
gst_object_unref (conv);
return res;
}

View File

@ -1,68 +0,0 @@
/* GStreamer FFTW-based signal-to-spectrum converter
* Copyright (C) 2006 Joseph Rabinoff <bobqwatson@yahoo.com>
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef __GST_FFTWSPECTRUM_H__
#define __GST_FFTWSPECTRUM_H__
#include <gst/gst.h>
#include <fftw3.h>
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_FFTWSPECTRUM \
(gst_fftwspectrum_get_type())
#define GST_FFTWSPECTRUM(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFTWSPECTRUM,GstFFTWSpectrum))
#define GST_FFTWSPECTRUM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFTWSPECTRUM,GstFFTWSpectrumClass))
typedef struct _GstFFTWSpectrum GstFFTWSpectrum;
typedef struct _GstFFTWSpectrumClass GstFFTWSpectrumClass;
struct _GstFFTWSpectrum
{
GstElement element;
GstPad *sinkpad, *srcpad;
/* Stream data */
gint rate, size, step;
/* Actual queued (incoming) stream */
gdouble *samples;
gint numsamples;
GstClockTime timestamp; /* Timestamp of the first sample */
guint64 offset; /* Offset of the first sample */
/* State data for fftw */
double *fftw_in;
double *fftw_out;
fftw_plan fftw_plan;
/* Properties */
gint32 def_size, def_step;
gboolean hi_q;
};
struct _GstFFTWSpectrumClass
{
GstElementClass parent_class;
};
GType gst_fftwspectrum_get_type (void);
G_END_DECLS
#endif /* __GST_FFTWSPECTRUM_H__ */

View File

@ -1,673 +0,0 @@
/* GStreamer spectrum analysis toy
* Copyright (C) 2006 Joseph Rabinoff <bobqwatson@yahoo.com>
* Some code copyright (C) 2005 Gav Wood
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* SECTION:element-moodbar
*
* <refsect2>
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch filesrc location=test.mp3 ! mad ! audioconvert ! fftwspectrum ! moodbar height=50 ! pngenc ! filesink location=test.png
* </programlisting>
* </para>
* </refsect2>
*/
/* This plugin is based on the Moodbar code in Amarok version 1.4.0a,
* written by Gav Wood. The algorithm is basically the same as the
* one applied there, and the normalizing code below is taken directly
* from Gav Wood's Exscalibar package.
*/
/* This plugin takes a frequency-domain stream, does some simple
* analysis, and returns a string of (unsigned char) rgb triples
* that represent the magnitude of various sections of the stream.
* Since we have to perform some normalization, we queue up all
* of our analysis until we get an EOS event, at which point we
* normalize and do the output. If a max-width is specified, the
* output is scaled down to the desired width if necessary.
*/
/* More precisely, the analysis performed is as follows:
* (1) the spectrum is broken into 24 parts, called "bark bands"
* (Gav's terminology), as given in bark_bands below
* (2) we compute the size of the first 8 bark bands and store
* that as the "red" component; similarly for blue and green
* (3) after receiving an EOS, we normalize all of the analysis
* done in (1) and (2) and return a stream of rgb triples
* (application/x-raw-rgb)
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include <string.h>
#include <math.h>
#include "gstmoodbar.h"
#include "spectrum.h"
GST_DEBUG_CATEGORY (gst_moodbar_debug);
#define GST_CAT_DEFAULT gst_moodbar_debug
/* Filter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_HEIGHT,
ARG_MAX_WIDTH
};
static GstStaticPadTemplate sink_factory
= GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
( SPECTRUM_FREQ_CAPS )
);
static GstStaticPadTemplate src_factory
= GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
( "video/x-raw-rgb, "
"bpp = (int) 24, "
"depth = (int) 24, "
"height = (int) [ 1, MAX ], "
"width = (int) [ 1, MAX ], "
"framerate = (fraction) 0/1"
)
);
GST_BOILERPLATE (GstMoodbar, gst_moodbar, GstElement,
GST_TYPE_ELEMENT);
static void gst_moodbar_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_moodbar_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static gboolean gst_moodbar_set_sink_caps (GstPad *pad, GstCaps *caps);
static gboolean gst_moodbar_sink_event (GstPad *pad, GstEvent *event);
static GstFlowReturn gst_moodbar_chain (GstPad *pad, GstBuffer *buf);
static GstStateChangeReturn gst_moodbar_change_state (GstElement *element,
GstStateChange transition);
static void gst_moodbar_finish (GstMoodbar *mood);
/* This is a failsafe so we don't eat up all of a computer's memory
* if we hit an endless stream. */
#define MAX_TRIPLES (1024*1024*4)
#define NUMFREQS(mood) ((mood)->size/2+1)
/* Allocate mood->r, mood->g, and mood->b in chunks of this many */
#define FRAME_CHUNK 1000
/* Default height of the output image */
#define HEIGHT_DEFAULT 1
/* Default max-width of the output image, or 0 for no rescaling */
#define MAX_WIDTH_DEFAULT 0
/* We use this table to break up the incoming spectrum into segments */
static const guint bark_bands[24]
= { 100, 200, 300, 400, 510, 630, 770, 920,
1080, 1270, 1480, 1720, 2000, 2320, 2700, 3150,
3700, 4400, 5300, 6400, 7700, 9500, 12000, 15500 };
/***************************************************************/
/* GObject boilerplate stuff */
/***************************************************************/
static void
gst_moodbar_base_init (gpointer gclass)
{
static GstElementDetails element_details =
{
"Moodbar analyzer",
"Filter/Converter/Moodbar",
"Convert a spectrum into a stream of (uchar) rgb triples representing its \"mood\"",
"Joe Rabinoff <bobqwatson@yahoo.com>"
};
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details (element_class, &element_details);
}
/* initialize the plugin's class */
static void
gst_moodbar_class_init (GstMoodbarClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = gst_moodbar_set_property;
gobject_class->get_property = gst_moodbar_get_property;
g_object_class_install_property (gobject_class, ARG_HEIGHT,
g_param_spec_int ("height", "Image height",
"The height of the resulting raw image",
1, G_MAXINT32, HEIGHT_DEFAULT, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_MAX_WIDTH,
g_param_spec_int ("max-width", "Image maximum width",
"The maximum width of the resulting raw image, or 0 for no rescaling",
0, G_MAXINT32, MAX_WIDTH_DEFAULT, G_PARAM_READWRITE));
gstelement_class->change_state
= GST_DEBUG_FUNCPTR (gst_moodbar_change_state);
}
/* initialize the new element
* instantiate pads and add them to element
* set functions
* initialize structure
*/
static void
gst_moodbar_init (GstMoodbar *mood, GstMoodbarClass *gclass)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (mood);
mood->sinkpad =
gst_pad_new_from_template
(gst_element_class_get_pad_template (klass, "sink"), "sink");
gst_pad_set_setcaps_function (mood->sinkpad,
GST_DEBUG_FUNCPTR (gst_moodbar_set_sink_caps));
gst_pad_set_event_function (mood->sinkpad,
GST_DEBUG_FUNCPTR (gst_moodbar_sink_event));
gst_pad_set_chain_function (mood->sinkpad,
GST_DEBUG_FUNCPTR (gst_moodbar_chain));
mood->srcpad =
gst_pad_new_from_template
(gst_element_class_get_pad_template (klass, "src"), "src");
gst_element_add_pad (GST_ELEMENT (mood), mood->sinkpad);
gst_element_add_pad (GST_ELEMENT (mood), mood->srcpad);
/* These are set once the (sink) capabilities are determined */
mood->rate = 0;
mood->size = 0;
mood->barkband_table = NULL;
/* These are allocated when we change to PAUSED */
mood->r = NULL;
mood->g = NULL;
mood->b = NULL;
mood->numframes = 0;
/* Property */
mood->height = HEIGHT_DEFAULT;
mood->max_width = MAX_WIDTH_DEFAULT;
}
static void gst_moodbar_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
GstMoodbar *mood = GST_MOODBAR (object);
switch (prop_id)
{
case ARG_HEIGHT:
mood->height = (guint) g_value_get_int (value);
break;
case ARG_MAX_WIDTH:
mood->max_width = (guint) g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void gst_moodbar_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
GstMoodbar *mood = GST_MOODBAR (object);
switch (prop_id)
{
case ARG_HEIGHT:
g_value_set_int (value, (int) mood->height);
break;
case ARG_MAX_WIDTH:
g_value_set_int (value, (int) mood->max_width);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/***************************************************************/
/* Pad handling */
/***************************************************************/
/* This calculates a table that caches which bark band slot each
* incoming band is supposed to go in. */
static void
calc_barkband_table (GstMoodbar *mood)
{
guint i;
guint barkband = 0;
/* Avoid divide-by-zero */
if (!mood->size || !mood->rate)
return;
if (mood->barkband_table)
g_free (mood->barkband_table);
mood->barkband_table = g_malloc (NUMFREQS (mood) * sizeof (guint));
for (i = 0; i < NUMFREQS (mood); ++i)
{
if (barkband < 23 &&
(guint) GST_SPECTRUM_BAND_FREQ (i, mood->size, mood->rate)
>= bark_bands[barkband])
barkband++;
mood->barkband_table[i] = barkband;
/*
GST_LOG ("Band %d (frequency %f) -> barkband %d (frequency %d)",
i, GST_SPECTRUM_BAND_FREQ (i, mood->size, mood->rate),
barkband, bark_bands[barkband]);
*/
}
}
/* Setting the sink caps just gets the rate and size parameters.
* Note that we do not support upstream caps renegotiation, since
* we could only possibly scale the height anyway.
*/
static gboolean
gst_moodbar_set_sink_caps (GstPad *pad, GstCaps *caps)
{
GstMoodbar *mood;
GstStructure *newstruct;
gint rate, size;
gboolean res = FALSE;
mood = GST_MOODBAR (gst_pad_get_parent (pad));
newstruct = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (newstruct, "rate", &rate) ||
!gst_structure_get_int (newstruct, "size", &size))
goto out;
res = TRUE;
mood->rate = rate;
mood->size = (guint) size;
calc_barkband_table (mood);
out:
gst_object_unref (mood);
return res;
}
static gboolean
gst_moodbar_sink_event (GstPad *pad, GstEvent *event)
{
GstMoodbar *mood;
gboolean res = TRUE;
mood = GST_MOODBAR (gst_pad_get_parent (pad));
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
gst_moodbar_finish (mood);
res = gst_pad_push_event (mood->srcpad, event);
gst_object_unref (mood);
return res;
}
/***************************************************************/
/* Actual analysis */
/***************************************************************/
static GstStateChangeReturn
gst_moodbar_change_state (GstElement *element, GstStateChange transition)
{
GstMoodbar *mood = GST_MOODBAR (element);
GstStateChangeReturn res;
switch (transition)
{
case GST_STATE_CHANGE_NULL_TO_READY:
calc_barkband_table (mood);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
mood->r = (gdouble *) g_malloc (FRAME_CHUNK * sizeof(gdouble));
mood->g = (gdouble *) g_malloc (FRAME_CHUNK * sizeof(gdouble));
mood->b = (gdouble *) g_malloc (FRAME_CHUNK * sizeof(gdouble));
mood->numframes = 0;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
default:
break;
}
res = parent_class->change_state (element, transition);
switch (transition)
{
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
g_free (mood->r);
g_free (mood->g);
g_free (mood->b);
mood->r = NULL;
mood->g = NULL;
mood->b = NULL;
mood->numframes = 0;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
g_free (mood->barkband_table);
mood->barkband_table = NULL;
break;
default:
break;
}
return res;
}
/* We allocate r, g, b frames in chunks of FRAME_CHUNK so we don't
* have to realloc every time a buffer comes in.
*/
static gboolean
allocate_another_frame (GstMoodbar *mood)
{
mood->numframes++;
/* Failsafe */
if (mood->numframes == MAX_TRIPLES)
return FALSE;
if(mood->numframes % FRAME_CHUNK == 0)
{
guint size = (mood->numframes + FRAME_CHUNK) * sizeof (gdouble);
mood->r = (gdouble *) g_realloc (mood->r, size);
mood->g = (gdouble *) g_realloc (mood->g, size);
mood->b = (gdouble *) g_realloc (mood->b, size);
if (mood->r == NULL || mood->g == NULL || mood->b == NULL)
return FALSE;
}
return TRUE;
}
/* This function does most of the analysis on the spectra we
* get as input and caches them. We actually push buffers
* once we receive an EOS signal.
*/
static GstFlowReturn
gst_moodbar_chain (GstPad *pad, GstBuffer *buf)
{
GstMoodbar *mood = GST_MOODBAR (gst_pad_get_parent (pad));
guint i;
gdouble amplitudes[24], rgb[3] = {0.f, 0.f, 0.f};
gdouble *out, real, imag;
guint numfreqs = NUMFREQS (mood);
if (GST_BUFFER_SIZE (buf) != numfreqs * sizeof (gdouble) * 2)
{
gst_object_unref (mood);
return GST_FLOW_ERROR;
}
out = (gdouble *) GST_BUFFER_DATA (buf);
if (!allocate_another_frame (mood))
return GST_FLOW_ERROR;
/* Calculate total amplitudes for the different bark bands */
for (i = 0; i < 24; ++i)
amplitudes[i] = 0.f;
for (i = 0; i < numfreqs; ++i)
{
real = out[2*i]; imag = out[2*i + 1];
amplitudes[mood->barkband_table[i]] += sqrtf (real*real + imag*imag);
}
/* Now divide the bark bands into thirds and compute their total
* amplitudes */
for (i = 0; i < 24; ++i)
rgb[i/8] += amplitudes[i] * amplitudes[i];
rgb[0] = sqrtf (rgb[0]);
rgb[1] = sqrtf (rgb[1]);
rgb[2] = sqrtf (rgb[2]);
mood->r[mood->numframes] = rgb[0];
mood->g[mood->numframes] = rgb[1];
mood->b[mood->numframes] = rgb[2];
gst_buffer_unref (buf);
gst_object_unref (mood);
return GST_FLOW_OK;
}
/* The normalization code was copied from Gav Wood's Exscalibar
* library, normalise.cpp
*/
static void
normalize (gdouble *vals, guint numvals)
{
gdouble mini, maxi, tu = 0.f, tb = 0.f;
gdouble avgu = 0.f, avgb = 0.f, delta, avg = 0.f;
gdouble avguu = 0.f, avgbb = 0.f;
guint i;
gint t = 0;
if (!numvals)
return;
mini = maxi = vals[0];
for (i = 1; i < numvals; i++)
{
if (vals[i] > maxi)
maxi = vals[i];
else if (vals[i] < mini)
mini = vals[i];
}
for (i = 0; i < numvals; i++)
{
if(vals[i] != mini && vals[i] != maxi)
{
avg += vals[i] / ((gdouble) numvals);
t++;
}
}
for (i = 0; i < numvals; i++)
{
if (vals[i] != mini && vals[i] != maxi)
{
if (vals[i] > avg)
{
avgu += vals[i];
tu++;
}
else
{
avgb += vals[i];
tb++;
}
}
}
avgu /= (gdouble) tu;
avgb /= (gdouble) tb;
tu = 0.f;
tb = 0.f;
for (i = 0; i < numvals; i++)
{
if (vals[i] != mini && vals[i] != maxi)
{
if (vals[i] > avgu)
{
avguu += vals[i];
tu++;
}
else if (vals[i] < avgb)
{
avgbb += vals[i];
tb++;
}
}
}
avguu /= (gdouble) tu;
avgbb /= (gdouble) tb;
mini = MAX (avg + (avgb - avg) * 2.f, avgbb);
maxi = MIN (avg + (avgu - avg) * 2.f, avguu);
delta = maxi - mini;
if (delta == 0.f)
delta = 1.f;
for (i = 0; i < numvals; i++)
vals[i] = isfinite (vals[i]) ? MIN(1.f, MAX(0.f, (vals[i] - mini) / delta))
: 0.f;
}
/* This function normalizes all of the cached r,g,b data and
* finally pushes a monster buffer with all of our output.
*/
static void
gst_moodbar_finish (GstMoodbar *mood)
{
GstBuffer *buf;
guchar *data;
guint line;
guint output_width;
if (mood->max_width == 0
|| mood->numframes <= mood->max_width)
output_width = mood->numframes;
else
output_width = mood->max_width;
normalize (mood->r, mood->numframes);
normalize (mood->g, mood->numframes);
normalize (mood->b, mood->numframes);
buf = gst_buffer_new_and_alloc
(output_width * mood->height * 3 * sizeof (guchar));
if (!buf)
return;
/* Don't set the timestamp, duration, etc. since it's irrelevant */
GST_BUFFER_OFFSET (buf) = 0;
data = (guchar *) GST_BUFFER_DATA (buf);
gdouble r, g, b;
guint i, j, n;
guint start, end;
for (line = 0; line < mood->height; ++line)
{
for (i = 0; i < output_width; ++i)
{
r = 0.f; g = 0.f; b = 0.f;
start = i * mood->numframes / output_width;
end = (i + 1) * mood->numframes / output_width;
if ( start == end )
end = start + 1;
for( j = start; j < end; j++ )
{
r += mood->r[j] * 255.f;
g += mood->g[j] * 255.f;
b += mood->b[j] * 255.f;
}
n = end - start;
*(data++) = (guchar) (r / ((gdouble) n));
*(data++) = (guchar) (g / ((gdouble) n));
*(data++) = (guchar) (b / ((gdouble) n));
}
}
{ /* Now we (finally) know the width of the image we're pushing */
GstCaps *caps = gst_caps_copy (gst_pad_get_caps (mood->srcpad));
gboolean res;
gst_caps_set_simple (caps, "width", G_TYPE_INT, output_width, NULL);
gst_caps_set_simple (caps, "height", G_TYPE_INT, mood->height, NULL);
res = gst_pad_set_caps (mood->srcpad, caps);
if (res)
gst_buffer_set_caps (buf, caps);
gst_caps_unref (caps);
if (!res)
return;
}
gst_pad_push (mood->srcpad, buf);
}

View File

@ -1,63 +0,0 @@
/* GStreamer spectrum analysis toy
* Copyright (C) 2006 Joseph Rabinoff <bobqwatson@yahoo.com>
* Some code copyright (C) 2005 Gav Wood
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef __GST_MOODBAR_H__
#define __GST_MOODBAR_H__
#include <gst/gst.h>
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_MOODBAR \
(gst_moodbar_get_type())
#define GST_MOODBAR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MOODBAR,GstMoodbar))
#define GST_MOODBAR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MOODBAR,GstMoodbarClass))
typedef struct _GstMoodbar GstMoodbar;
typedef struct _GstMoodbarClass GstMoodbarClass;
struct _GstMoodbar
{
GstElement element;
GstPad *sinkpad, *srcpad;
/* Stream data */
gint rate, size;
/* Cached band -> bark band table */
guint *barkband_table;
/* Queued moodbar data */
gdouble *r, *g, *b;
guint numframes;
/* Property */
guint height;
guint max_width;
};
struct _GstMoodbarClass
{
GstElementClass parent_class;
};
GType gst_moodbar_get_type (void);
G_END_DECLS
#endif /* __GST_MOODBAR_H__ */

48
gst/moodbar/plugin.cpp Normal file
View File

@ -0,0 +1,48 @@
/* This file is part of Clementine.
Copyright 2014, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gst/gst.h>
#include "gstfastspectrum.h"
#include "plugin.h"
namespace {
static gboolean plugin_init(GstPlugin* plugin) {
if (!gst_element_register(plugin, "fastspectrum",
GST_RANK_NONE, GST_TYPE_FASTSPECTRUM)) {
return FALSE;
}
return TRUE;
}
} // namespace
int gstfastspectrum_register_static() {
return gst_plugin_register_static(
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"fastspectrum",
"Fast spectrum analyzer for generating Moodbars",
plugin_init,
"0.1",
"GPL",
"FastSpectrum",
"FastSpectrum",
"https://www.clementine-player.org");
}

25
gst/moodbar/plugin.h Normal file
View File

@ -0,0 +1,25 @@
/* This file is part of Clementine.
Copyright 2014, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GST_MOODBAR_PLUGIN_H_
#define GST_MOODBAR_PLUGIN_H_
extern "C" {
int gstfastspectrum_register_static();
}
#endif // GST_MOODBAR_PLUGIN_H_

View File

@ -1,71 +0,0 @@
/* GStreamer moodbar plugin globals
* Copyright (C) 2006 Joseph Rabinoff <bobqwatson@yahoo.com>
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include "gstfftwspectrum.h"
#include "gstmoodbar.h"
#include "spectrum.h"
/***************************************************************/
/* Plugin managing */
/***************************************************************/
GST_DEBUG_CATEGORY_EXTERN (gst_fftwspectrum_debug);
GST_DEBUG_CATEGORY_EXTERN (gst_moodbar_debug);
/* entry point to initialize the plug-in
* initialize the plug-in itself
* register the element factories and pad templates
* register the features
*
* exchange the string 'plugin' with your elemnt name
*/
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "fftwspectrum",
GST_RANK_NONE, GST_TYPE_FFTWSPECTRUM))
return FALSE;
if (!gst_element_register (plugin, "moodbar",
GST_RANK_NONE, GST_TYPE_MOODBAR))
return FALSE;
GST_DEBUG_CATEGORY_INIT (gst_fftwspectrum_debug, "fftwspectrum",
0, "FFTW Sample-to-Spectrum Converter Plugin");
GST_DEBUG_CATEGORY_INIT (gst_moodbar_debug, "moodbar",
0, "Moodbar analyzer");
return TRUE;
}
void gstmoodbar_register_static() {
gst_plugin_register_static(
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"moodbar",
"Frequency analyzer and converter plugin",
plugin_init,
"0.1.2",
"GPL",
"Moodbar",
"Moodbar",
"http://amarok.kde.org/wiki/Moodbar");
}

View File

@ -1,67 +0,0 @@
/* GStreamer moodbar plugin globals
* Copyright (C) 2006 Joseph Rabinoff <bobqwatson@yahoo.com>
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef __SPECTRUM_H__
#define __SPECTRUM_H__
/* Since fftwspectrum and fftwunspectrum are supposed to be
* opposites, they'll be using the same caps: */
#define SPECTRUM_SIGNAL_CAPS "audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) 1, " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 64, " \
"signed = (boolean) true"
/* audio/x-spectrum-complex-float is an array of complex floats. A
* complex float is just a pair (r, i) of a real float and an
* imaginary float, each with the specified width. The properties
* are as follows:
* rate: the rate of the original signal
* size: the number of signals processed to make the current buffer
* step: the number of signals advanced after the current buffer
* width: the size of the real & imaginary parts of the data
* endianness: ditto
*
* Each audio/x-spectrum-complex-float buffer represents the Fourier
* transform of size samples, and hence _must_ have exactly
* floor(size/2) + 1 complex floats in it; in other words, its
* buffer size must be (floor(size/2) + 1) * 2 * sizeof(gfloat)
*/
#define SPECTRUM_FREQ_CAPS "audio/x-spectrum-complex-float, " \
"rate = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 64, " \
"size = (int) [ 1, MAX ], " \
"step = (int) [ 1, MAX ]"
/* Given a band number from a spectrum made from size audio
* samples at the given rate, return the frequency that band
* corresponds to.
*/
#define GST_SPECTRUM_BAND_FREQ(band, size, rate) \
(((gfloat)(band))*((gfloat)(rate))/((gfloat)(size)))
#ifdef __cplusplus
extern "C" {
#endif
void gstmoodbar_register_static();
#ifdef __cplusplus
}
#endif
#endif /* __SPECTRUM_H__ */

View File

@ -75,8 +75,10 @@ set(SOURCES
analyzers/blockanalyzer.cpp
analyzers/boomanalyzer.cpp
analyzers/nyancatanalyzer.cpp
analyzers/rainbowdashanalyzer.cpp
analyzers/sonogram.cpp
analyzers/turbine.cpp
analyzers/fht.cpp
core/appearance.cpp
core/application.cpp
@ -87,7 +89,6 @@ set(SOURCES
core/deletefiles.cpp
core/filesystemmusicstorage.cpp
core/filesystemwatcherinterface.cpp
core/fht.cpp
core/globalshortcutbackend.cpp
core/globalshortcuts.cpp
core/gnomeglobalshortcutbackend.cpp
@ -164,48 +165,49 @@ set(SOURCES
globalsearch/suggestionwidget.cpp
globalsearch/urlsearchprovider.cpp
internet/cloudfilesearchprovider.cpp
internet/cloudfileservice.cpp
internet/digitallyimportedclient.cpp
internet/digitallyimportedservicebase.cpp
internet/digitallyimportedsettingspage.cpp
internet/digitallyimportedurlhandler.cpp
internet/geolocator.cpp
internet/groovesharkradio.cpp
internet/groovesharkservice.cpp
internet/groovesharksettingspage.cpp
internet/groovesharkurlhandler.cpp
internet/icecastbackend.cpp
internet/icecastfilterwidget.cpp
internet/icecastmodel.cpp
internet/icecastservice.cpp
internet/internetmodel.cpp
internet/internetplaylistitem.cpp
internet/internetservice.cpp
internet/internetview.cpp
internet/internetviewcontainer.cpp
internet/jamendodynamicplaylist.cpp
internet/jamendoplaylistitem.cpp
internet/jamendoservice.cpp
internet/localredirectserver.cpp
internet/magnatunedownloaddialog.cpp
internet/magnatuneplaylistitem.cpp
internet/magnatuneservice.cpp
internet/magnatunesettingspage.cpp
internet/magnatuneurlhandler.cpp
internet/oauthenticator.cpp
internet/savedradio.cpp
internet/searchboxwidget.cpp
internet/somafmservice.cpp
internet/somafmurlhandler.cpp
internet/soundcloudservice.cpp
internet/soundcloudsettingspage.cpp
internet/spotifyserver.cpp
internet/spotifyservice.cpp
internet/spotifysettingspage.cpp
internet/subsonicservice.cpp
internet/subsonicsettingspage.cpp
internet/subsonicurlhandler.cpp
internet/core/cloudfilesearchprovider.cpp
internet/core/cloudfileservice.cpp
internet/digitally/digitallyimportedclient.cpp
internet/digitally/digitallyimportedservicebase.cpp
internet/digitally/digitallyimportedsettingspage.cpp
internet/digitally/digitallyimportedurlhandler.cpp
internet/core/geolocator.cpp
internet/grooveshark/groovesharkradio.cpp
internet/grooveshark/groovesharkservice.cpp
internet/grooveshark/groovesharksettingspage.cpp
internet/grooveshark/groovesharkurlhandler.cpp
internet/icecast/icecastbackend.cpp
internet/icecast/icecastfilterwidget.cpp
internet/icecast/icecastmodel.cpp
internet/icecast/icecastservice.cpp
internet/core/internetmodel.cpp
internet/core/internetplaylistitem.cpp
internet/core/internetservice.cpp
internet/core/internetshowsettingspage.cpp
internet/core/internetview.cpp
internet/core/internetviewcontainer.cpp
internet/jamendo/jamendodynamicplaylist.cpp
internet/jamendo/jamendoplaylistitem.cpp
internet/jamendo/jamendoservice.cpp
internet/core/localredirectserver.cpp
internet/magnatune/magnatunedownloaddialog.cpp
internet/magnatune/magnatuneplaylistitem.cpp
internet/magnatune/magnatuneservice.cpp
internet/magnatune/magnatunesettingspage.cpp
internet/magnatune/magnatuneurlhandler.cpp
internet/core/oauthenticator.cpp
internet/internetradio/savedradio.cpp
internet/core/searchboxwidget.cpp
internet/somafm/somafmservice.cpp
internet/somafm/somafmurlhandler.cpp
internet/soundcloud/soundcloudservice.cpp
internet/soundcloud/soundcloudsettingspage.cpp
internet/spotify/spotifyserver.cpp
internet/spotify/spotifyservice.cpp
internet/spotify/spotifysettingspage.cpp
internet/subsonic/subsonicservice.cpp
internet/subsonic/subsonicsettingspage.cpp
internet/subsonic/subsonicurlhandler.cpp
library/groupbydialog.cpp
library/library.cpp
@ -232,6 +234,7 @@ set(SOURCES
networkremote/networkremotehelper.cpp
networkremote/outgoingdatacreator.cpp
networkremote/remoteclient.cpp
networkremote/songsender.cpp
networkremote/tcpremoteclient.cpp
networkremote/webremoteclient.cpp
networkremote/zeroconf.cpp
@ -249,6 +252,7 @@ set(SOURCES
playlist/playlistlistmodel.cpp
playlist/playlistlistview.cpp
playlist/playlistmanager.cpp
playlist/playlistsaveoptionsdialog.cpp
playlist/playlistsequence.cpp
playlist/playlisttabbar.cpp
playlist/playlistundocommands.cpp
@ -269,27 +273,28 @@ set(SOURCES
playlistparsers/xmlparser.cpp
playlistparsers/xspfparser.cpp
podcasts/addpodcastbyurl.cpp
podcasts/addpodcastdialog.cpp
podcasts/addpodcastpage.cpp
podcasts/fixedopmlpage.cpp
podcasts/gpoddersearchpage.cpp
podcasts/gpoddersync.cpp
podcasts/gpoddertoptagsmodel.cpp
podcasts/gpoddertoptagspage.cpp
podcasts/itunessearchpage.cpp
podcasts/podcast.cpp
podcasts/podcastbackend.cpp
podcasts/podcastdiscoverymodel.cpp
podcasts/podcastdownloader.cpp
podcasts/podcastepisode.cpp
podcasts/podcastinfowidget.cpp
podcasts/podcastservice.cpp
podcasts/podcastservicemodel.cpp
podcasts/podcastsettingspage.cpp
podcasts/podcastparser.cpp
podcasts/podcastupdater.cpp
podcasts/podcasturlloader.cpp
internet/podcasts/addpodcastbyurl.cpp
internet/podcasts/addpodcastdialog.cpp
internet/podcasts/addpodcastpage.cpp
internet/podcasts/fixedopmlpage.cpp
internet/podcasts/gpoddersearchpage.cpp
internet/podcasts/gpoddersync.cpp
internet/podcasts/gpoddertoptagsmodel.cpp
internet/podcasts/gpoddertoptagspage.cpp
internet/podcasts/itunessearchpage.cpp
internet/podcasts/podcast.cpp
internet/podcasts/podcastbackend.cpp
internet/podcasts/podcastdiscoverymodel.cpp
internet/podcasts/podcastdeleter.cpp
internet/podcasts/podcastdownloader.cpp
internet/podcasts/podcastepisode.cpp
internet/podcasts/podcastinfowidget.cpp
internet/podcasts/podcastservice.cpp
internet/podcasts/podcastservicemodel.cpp
internet/podcasts/podcastsettingspage.cpp
internet/podcasts/podcastparser.cpp
internet/podcasts/podcastupdater.cpp
internet/podcasts/podcasturlloader.cpp
smartplaylists/generator.cpp
smartplaylists/generatorinserter.cpp
@ -410,6 +415,7 @@ set(HEADERS
analyzers/blockanalyzer.h
analyzers/boomanalyzer.h
analyzers/nyancatanalyzer.h
analyzers/rainbowdashanalyzer.h
analyzers/sonogram.h
analyzers/turbine.h
@ -473,44 +479,45 @@ set(HEADERS
globalsearch/spotifysearchprovider.h
globalsearch/suggestionwidget.h
internet/cloudfileservice.h
internet/digitallyimportedclient.h
internet/digitallyimportedservicebase.h
internet/digitallyimportedsettingspage.h
internet/geolocator.h
internet/groovesharkservice.h
internet/groovesharksettingspage.h
internet/groovesharkurlhandler.h
internet/icecastbackend.h
internet/icecastfilterwidget.h
internet/icecastmodel.h
internet/icecastservice.h
internet/internetmimedata.h
internet/internetmodel.h
internet/internetservice.h
internet/internetsongmimedata.h
internet/internetview.h
internet/internetviewcontainer.h
internet/jamendodynamicplaylist.h
internet/jamendoservice.h
internet/localredirectserver.h
internet/magnatunedownloaddialog.h
internet/magnatuneservice.h
internet/magnatunesettingspage.h
internet/oauthenticator.h
internet/savedradio.h
internet/scrobbler.h
internet/searchboxwidget.h
internet/somafmservice.h
internet/somafmurlhandler.h
internet/soundcloudservice.h
internet/soundcloudsettingspage.h
internet/spotifyserver.h
internet/spotifyservice.h
internet/spotifysettingspage.h
internet/subsonicservice.h
internet/subsonicsettingspage.h
internet/subsonicurlhandler.h
internet/core/cloudfileservice.h
internet/digitally/digitallyimportedclient.h
internet/digitally/digitallyimportedservicebase.h
internet/digitally/digitallyimportedsettingspage.h
internet/core/geolocator.h
internet/grooveshark/groovesharkservice.h
internet/grooveshark/groovesharksettingspage.h
internet/grooveshark/groovesharkurlhandler.h
internet/icecast/icecastbackend.h
internet/icecast/icecastfilterwidget.h
internet/icecast/icecastmodel.h
internet/icecast/icecastservice.h
internet/core/internetmimedata.h
internet/core/internetmodel.h
internet/core/internetservice.h
internet/core/internetshowsettingspage.h
internet/core/internetsongmimedata.h
internet/core/internetview.h
internet/core/internetviewcontainer.h
internet/jamendo/jamendodynamicplaylist.h
internet/jamendo/jamendoservice.h
internet/core/localredirectserver.h
internet/magnatune/magnatunedownloaddialog.h
internet/magnatune/magnatuneservice.h
internet/magnatune/magnatunesettingspage.h
internet/core/oauthenticator.h
internet/internetradio/savedradio.h
internet/core/scrobbler.h
internet/core/searchboxwidget.h
internet/somafm/somafmservice.h
internet/somafm/somafmurlhandler.h
internet/soundcloud/soundcloudservice.h
internet/soundcloud/soundcloudsettingspage.h
internet/spotify/spotifyserver.h
internet/spotify/spotifyservice.h
internet/spotify/spotifysettingspage.h
internet/subsonic/subsonicservice.h
internet/subsonic/subsonicsettingspage.h
internet/subsonic/subsonicurlhandler.h
library/groupbydialog.h
library/library.h
@ -528,11 +535,12 @@ set(HEADERS
musicbrainz/tagfetcher.h
networkremote/clementinewebpage.h
networkremote/networkremotehelper.h
networkremote/networkremote.h
networkremote/incomingdataparser.h
networkremote/networkremote.h
networkremote/networkremotehelper.h
networkremote/outgoingdatacreator.h
networkremote/remoteclient.h
networkremote/songsender.h
networkremote/tcpremoteclient.h
networkremote/webremoteclient.h
@ -548,6 +556,7 @@ set(HEADERS
playlist/playlistlistmodel.h
playlist/playlistlistview.h
playlist/playlistmanager.h
playlist/playlistsaveoptionsdialog.h
playlist/playlistsequence.h
playlist/playlisttabbar.h
playlist/playlistview.h
@ -565,24 +574,25 @@ set(HEADERS
playlistparsers/plsparser.h
playlistparsers/xspfparser.h
podcasts/addpodcastbyurl.h
podcasts/addpodcastdialog.h
podcasts/addpodcastpage.h
podcasts/fixedopmlpage.h
podcasts/gpoddersearchpage.h
podcasts/gpoddersync.h
podcasts/gpoddertoptagsmodel.h
podcasts/gpoddertoptagspage.h
podcasts/itunessearchpage.h
podcasts/podcastbackend.h
podcasts/podcastdiscoverymodel.h
podcasts/podcastdownloader.h
podcasts/podcastinfowidget.h
podcasts/podcastservice.h
podcasts/podcastservicemodel.h
podcasts/podcastsettingspage.h
podcasts/podcastupdater.h
podcasts/podcasturlloader.h
internet/podcasts/addpodcastbyurl.h
internet/podcasts/addpodcastdialog.h
internet/podcasts/addpodcastpage.h
internet/podcasts/fixedopmlpage.h
internet/podcasts/gpoddersearchpage.h
internet/podcasts/gpoddersync.h
internet/podcasts/gpoddertoptagsmodel.h
internet/podcasts/gpoddertoptagspage.h
internet/podcasts/itunessearchpage.h
internet/podcasts/podcastbackend.h
internet/podcasts/podcastdiscoverymodel.h
internet/podcasts/podcastdeleter.h
internet/podcasts/podcastdownloader.h
internet/podcasts/podcastinfowidget.h
internet/podcasts/podcastservice.h
internet/podcasts/podcastservicemodel.h
internet/podcasts/podcastsettingspage.h
internet/podcasts/podcastupdater.h
internet/podcasts/podcasturlloader.h
smartplaylists/generator.h
smartplaylists/generatorinserter.h
@ -693,16 +703,17 @@ set(UI
globalsearch/searchproviderstatuswidget.ui
globalsearch/suggestionwidget.ui
internet/digitallyimportedsettingspage.ui
internet/groovesharksettingspage.ui
internet/icecastfilterwidget.ui
internet/internetviewcontainer.ui
internet/magnatunedownloaddialog.ui
internet/magnatunesettingspage.ui
internet/searchboxwidget.ui
internet/soundcloudsettingspage.ui
internet/spotifysettingspage.ui
internet/subsonicsettingspage.ui
internet/digitally/digitallyimportedsettingspage.ui
internet/grooveshark/groovesharksettingspage.ui
internet/icecast/icecastfilterwidget.ui
internet/core/internetshowsettingspage.ui
internet/core/internetviewcontainer.ui
internet/magnatune/magnatunedownloaddialog.ui
internet/magnatune/magnatunesettingspage.ui
internet/core/searchboxwidget.ui
internet/soundcloud/soundcloudsettingspage.ui
internet/spotify/spotifysettingspage.ui
internet/subsonic/subsonicsettingspage.ui
library/groupbydialog.ui
library/libraryfilterwidget.ui
@ -711,16 +722,17 @@ set(UI
playlist/dynamicplaylistcontrols.ui
playlist/playlistcontainer.ui
playlist/playlistsaveoptionsdialog.ui
playlist/playlistlistcontainer.ui
playlist/playlistsequence.ui
playlist/queuemanager.ui
podcasts/addpodcastbyurl.ui
podcasts/addpodcastdialog.ui
podcasts/gpoddersearchpage.ui
podcasts/itunessearchpage.ui
podcasts/podcastinfowidget.ui
podcasts/podcastsettingspage.ui
internet/podcasts/addpodcastbyurl.ui
internet/podcasts/addpodcastdialog.ui
internet/podcasts/gpoddersearchpage.ui
internet/podcasts/itunessearchpage.ui
internet/podcasts/podcastinfowidget.ui
internet/podcasts/podcastsettingspage.ui
smartplaylists/querysearchpage.ui
smartplaylists/querysortpage.ui
@ -826,32 +838,32 @@ optional_source(ENABLE_VISUALISATIONS
optional_source(HAVE_LIBLASTFM
SOURCES
covers/lastfmcoverprovider.cpp
internet/fixlastfm.cpp
internet/lastfmcompat.cpp
internet/lastfmservice.cpp
internet/lastfmsettingspage.cpp
internet/lastfm/fixlastfm.cpp
internet/lastfm/lastfmcompat.cpp
internet/lastfm/lastfmservice.cpp
internet/lastfm/lastfmsettingspage.cpp
songinfo/echonestsimilarartists.cpp
songinfo/echonesttags.cpp
songinfo/lastfmtrackinfoprovider.cpp
songinfo/tagwidget.cpp
HEADERS
covers/lastfmcoverprovider.h
internet/lastfmservice.h
internet/lastfmsettingspage.h
internet/lastfm/lastfmservice.h
internet/lastfm/lastfmsettingspage.h
songinfo/echonestsimilarartists.h
songinfo/echonesttags.h
songinfo/lastfmtrackinfoprovider.h
songinfo/tagwidget.h
UI
internet/lastfmsettingspage.ui
internet/lastfm/lastfmsettingspage.ui
)
optional_source(HAVE_SPOTIFY_DOWNLOADER
SOURCES
internet/spotifyblobdownloader.cpp
internet/spotify/spotifyblobdownloader.cpp
HEADERS
internet/spotifyblobdownloader.h
internet/spotify/spotifyblobdownloader.h
INCLUDE_DIRECTORIES
${QCA_INCLUDE_DIRS}
)
@ -896,11 +908,6 @@ optional_source(LINUX SOURCES widgets/osd_x11.cpp)
if(HAVE_DBUS)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus)
# Hack to get it to generate interfaces without namespaces - required
# because otherwise org::freedesktop::UDisks and
# org::freedesktop::UDisks::Device conflict.
list(APPEND QT_DBUSXML2CPP_EXECUTABLE -N)
# MPRIS DBUS interfaces
qt4_add_dbus_adaptor(SOURCES
dbus/org.freedesktop.MediaPlayer.player.xml
@ -968,6 +975,10 @@ if(HAVE_DBUS)
# DeviceKit DBUS interfaces
if(HAVE_DEVICEKIT)
set_source_files_properties(dbus/org.freedesktop.UDisks.xml
PROPERTIES NO_NAMESPACE dbus/udisks)
set_source_files_properties(dbus/org.freedesktop.UDisks.Device.xml
PROPERTIES NO_NAMESPACE dbus/udisksdevice)
qt4_add_dbus_interface(SOURCES
dbus/org.freedesktop.UDisks.xml
dbus/udisks)
@ -1036,10 +1047,12 @@ optional_source(HAVE_AUDIOCD
SOURCES
devices/cddadevice.cpp
devices/cddalister.cpp
devices/cddasongloader.cpp
ui/ripcd.cpp
HEADERS
devices/cddadevice.h
devices/cddalister.h
devices/cddasongloader.h
ui/ripcd.h
UI
ui/ripcd.ui
@ -1060,6 +1073,7 @@ optional_source(HAVE_LIBMTP
# Moodbar support
optional_source(HAVE_MOODBAR
SOURCES
moodbar/moodbarbuilder.cpp
moodbar/moodbarcontroller.cpp
moodbar/moodbaritemdelegate.cpp
moodbar/moodbarloader.cpp
@ -1077,61 +1091,61 @@ optional_source(HAVE_MOODBAR
# Google Drive support
optional_source(HAVE_GOOGLE_DRIVE
SOURCES
internet/googledriveclient.cpp
internet/googledriveservice.cpp
internet/googledrivesettingspage.cpp
internet/googledriveurlhandler.cpp
internet/googledrive/googledriveclient.cpp
internet/googledrive/googledriveservice.cpp
internet/googledrive/googledrivesettingspage.cpp
internet/googledrive/googledriveurlhandler.cpp
HEADERS
internet/googledriveclient.h
internet/googledriveservice.h
internet/googledrivesettingspage.h
internet/googledriveurlhandler.h
internet/googledrive/googledriveclient.h
internet/googledrive/googledriveservice.h
internet/googledrive/googledrivesettingspage.h
internet/googledrive/googledriveurlhandler.h
UI
internet/googledrivesettingspage.ui
internet/googledrive/googledrivesettingspage.ui
)
# Dropbox support
optional_source(HAVE_DROPBOX
SOURCES
internet/dropboxauthenticator.cpp
internet/dropboxservice.cpp
internet/dropboxsettingspage.cpp
internet/dropboxurlhandler.cpp
internet/dropbox/dropboxauthenticator.cpp
internet/dropbox/dropboxservice.cpp
internet/dropbox/dropboxsettingspage.cpp
internet/dropbox/dropboxurlhandler.cpp
HEADERS
internet/dropboxauthenticator.h
internet/dropboxservice.h
internet/dropboxsettingspage.h
internet/dropboxurlhandler.h
internet/dropbox/dropboxauthenticator.h
internet/dropbox/dropboxservice.h
internet/dropbox/dropboxsettingspage.h
internet/dropbox/dropboxurlhandler.h
UI
internet/dropboxsettingspage.ui
internet/dropbox/dropboxsettingspage.ui
)
# Skydrive support
optional_source(HAVE_SKYDRIVE
SOURCES
internet/skydriveservice.cpp
internet/skydrivesettingspage.cpp
internet/skydriveurlhandler.cpp
internet/skydrive/skydriveservice.cpp
internet/skydrive/skydrivesettingspage.cpp
internet/skydrive/skydriveurlhandler.cpp
HEADERS
internet/skydriveservice.h
internet/skydrivesettingspage.h
internet/skydriveurlhandler.h
internet/skydrive/skydriveservice.h
internet/skydrive/skydrivesettingspage.h
internet/skydrive/skydriveurlhandler.h
UI
internet/skydrivesettingspage.ui
internet/skydrive/skydrivesettingspage.ui
)
# Box support
optional_source(HAVE_BOX
SOURCES
internet/boxservice.cpp
internet/boxsettingspage.cpp
internet/boxurlhandler.cpp
internet/box/boxservice.cpp
internet/box/boxsettingspage.cpp
internet/box/boxurlhandler.cpp
HEADERS
internet/boxservice.h
internet/boxsettingspage.h
internet/boxurlhandler.h
internet/box/boxservice.h
internet/box/boxsettingspage.h
internet/box/boxurlhandler.h
UI
internet/boxsettingspage.ui
internet/box/boxsettingspage.ui
)
# Vk.com support
@ -1140,25 +1154,42 @@ optional_source(HAVE_VK
${VREEN_INCLUDE_DIRS}
SOURCES
globalsearch/vksearchprovider.cpp
internet/vkconnection.cpp
internet/vkmusiccache.cpp
internet/vksearchdialog.cpp
internet/vkservice.cpp
internet/vksettingspage.cpp
internet/vkurlhandler.cpp
internet/vk/vkconnection.cpp
internet/vk/vkmusiccache.cpp
internet/vk/vksearchdialog.cpp
internet/vk/vkservice.cpp
internet/vk/vksettingspage.cpp
internet/vk/vkurlhandler.cpp
HEADERS
globalsearch/vksearchprovider.h
internet/vkconnection.h
internet/vkmusiccache.h
internet/vksearchdialog.h
internet/vkservice.h
internet/vksettingspage.h
internet/vkurlhandler.h
internet/vk/vkconnection.h
internet/vk/vkmusiccache.h
internet/vk/vksearchdialog.h
internet/vk/vkservice.h
internet/vk/vksettingspage.h
internet/vk/vkurlhandler.h
UI
internet/vksearchdialog.ui
internet/vksettingspage.ui
internet/vk/vksearchdialog.ui
internet/vk/vksettingspage.ui
)
# Seafile support
optional_source(HAVE_SEAFILE
SOURCES
internet/seafile/seafileservice.cpp
internet/seafile/seafilesettingspage.cpp
internet/seafile/seafileurlhandler.cpp
internet/seafile/seafiletree.cpp
HEADERS
internet/seafile/seafileservice.h
internet/seafile/seafilesettingspage.h
internet/seafile/seafileurlhandler.h
internet/seafile/seafiletree.h
UI
internet/seafile/seafilesettingspage.ui
)
# Pulse audio integration
optional_source(HAVE_LIBPULSE
INCLUDE_DIRECTORIES
@ -1256,7 +1287,6 @@ endif(HAVE_GIO)
if(HAVE_AUDIOCD)
target_link_libraries(clementine_lib ${CDIO_LIBRARIES})
target_link_libraries(clementine_lib ${GSTREAMER_CDDA_LIBRARIES})
endif(HAVE_AUDIOCD)
if(HAVE_MOODBAR)
@ -1390,6 +1420,8 @@ if (APPLE)
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Resources")
install(FILES ../dist/sparkle_pub.pem
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Resources")
install(FILES ../dist/cacert.pem
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Resources")
install(DIRECTORY "${QT_QTGUI_LIBRARY_RELEASE}/Versions/Current/Resources/"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Resources")
@ -1399,20 +1431,22 @@ if (APPLE)
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/Sparkle.framework")
endif (HAVE_SPARKLE)
install(FILES "${QT_QTCORE_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtCore.framework/Contents")
install(FILES "${QT_QTGUI_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtGui.framework/Contents")
install(FILES "${QT_QTNETWORK_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtNetwork.framework/Contents")
install(FILES "${QT_QTOPENGL_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtOpenGL.framework/Contents")
install(FILES "${QT_QTSQL_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtSql.framework/Contents")
install(FILES "${QT_QTSVG_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtSvg.framework/Contents")
install(FILES "${QT_QTXML_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtXml.framework/Contents")
foreach (plist_destination Versions/4/Resources Resources)
install(FILES "${QT_QTCORE_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtCore.framework/${plist_destination}")
install(FILES "${QT_QTGUI_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtGui.framework/${plist_destination}")
install(FILES "${QT_QTNETWORK_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtNetwork.framework/${plist_destination}")
install(FILES "${QT_QTOPENGL_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtOpenGL.framework/${plist_destination}")
install(FILES "${QT_QTSQL_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtSql.framework/${plist_destination}")
install(FILES "${QT_QTSVG_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtSvg.framework/${plist_destination}")
install(FILES "${QT_QTXML_LIBRARY_RELEASE}/Contents/Info.plist"
DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Frameworks/QtXml.framework/${plist_destination}")
endforeach()
if (HAVE_BREAKPAD)
install(DIRECTORY

View File

@ -1,3 +1,21 @@
/* This file is part of Clementine.
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "analyzer.h"
#include "engines/enginebase.h"

76
src/analyzers/analyzerbase.cpp Executable file → Normal file
View File

@ -1,25 +1,33 @@
/***************************************************************************
viswidget.cpp - description
-------------------
begin : Die Jan 7 2003
copyright : (C) 2003 by Max Howell
email : markey@web.de
***************************************************************************/
/* This file is part of Clementine.
Copyright 2003, Max Howell <max.howell@methylblue.com>
Copyright 2009, 2011-2012, David Sansome <me@davidsansome.com>
Copyright 2010, 2012, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Max Howell <max.howell@methylblue.com> 2003
*/
#include "analyzerbase.h"
#include <cmath> //interpolate()
#include <cmath>
#include <cstdint>
#include <QEvent> //event()
#include <QEvent>
#include <QPainter>
#include <QPaintEvent>
#include <QtDebug>
@ -34,10 +42,10 @@
// widget when you return control to it
// 4. if you want to manipulate the scope, reimplement transform()
// 5. for convenience <vector> <qpixmap.h> <qwdiget.h> are pre-included
// TODO make an INSTRUCTIONS file
// TODO(David Sansome): make an INSTRUCTIONS file
// can't mod scope in analyze you have to use transform
// TODO for 2D use setErasePixmap Qt function insetead of m_background
// TODO(John Maguire): for 2D use setErasePixmap Qt function insetead of m_background
// make the linker happy only for gcc < 4.0
#if !(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0)) && \
@ -60,8 +68,7 @@ void Analyzer::Base::hideEvent(QHideEvent*) { m_timer.stop(); }
void Analyzer::Base::showEvent(QShowEvent*) { m_timer.start(timeout(), this); }
void Analyzer::Base::transform(Scope& scope) // virtual
{
void Analyzer::Base::transform(Scope& scope) {
// this is a standard transformation that should give
// an FFT scope that has bands for pretty analyzers
@ -91,9 +98,9 @@ void Analyzer::Base::paintEvent(QPaintEvent* e) {
// convert to mono here - our built in analyzers need mono, but the
// engines provide interleaved pcm
for (uint x = 0; (int)x < m_fht->size(); ++x) {
for (uint x = 0; static_cast<int>(x) < m_fht->size(); ++x) {
m_lastScope[x] =
double(thescope[i] + thescope[i + 1]) / (2 * (1 << 15));
static_cast<double>(thescope[i] + thescope[i + 1]) / (2 * (1 << 15));
i += 2;
}
@ -150,22 +157,21 @@ int Analyzer::Base::resizeForBands(int bands) {
return m_fht->size() / 2;
}
void Analyzer::Base::demo(QPainter& p) // virtual
{
void Analyzer::Base::demo(QPainter& p) {
static int t = 201; // FIXME make static to namespace perhaps
if (t > 999) t = 1; // 0 = wasted calculations
if (t < 201) {
Scope s(32);
const double dt = double(t) / 200;
const double dt = static_cast<double>(t) / 200;
for (uint i = 0; i < s.size(); ++i)
s[i] = dt * (sin(M_PI + (i * M_PI) / s.size()) + 1.0);
analyze(p, s, new_frame_);
} else
} else {
analyze(p, Scope(32, 0), new_frame_);
}
++t;
}
@ -173,20 +179,19 @@ void Analyzer::Base::polishEvent() {
init(); // virtual
}
void Analyzer::interpolate(const Scope& inVec, Scope& outVec) // static
{
void Analyzer::interpolate(const Scope& inVec, Scope& outVec) {
double pos = 0.0;
const double step = (double)inVec.size() / outVec.size();
const double step = static_cast<double>(inVec.size()) / outVec.size();
for (uint i = 0; i < outVec.size(); ++i, pos += step) {
const double error = pos - std::floor(pos);
const unsigned long offset = (unsigned long)pos;
const uint64_t offset = static_cast<uint64_t>(pos);
unsigned long indexLeft = offset + 0;
uint64_t indexLeft = offset + 0;
if (indexLeft >= inVec.size()) indexLeft = inVec.size() - 1;
unsigned long indexRight = offset + 1;
uint64_t indexRight = offset + 1;
if (indexRight >= inVec.size()) indexRight = inVec.size() - 1;
@ -194,8 +199,7 @@ void Analyzer::interpolate(const Scope& inVec, Scope& outVec) // static
}
}
void Analyzer::initSin(Scope& v, const uint size) // static
{
void Analyzer::initSin(Scope& v, const uint size) {
double step = (M_PI * 2) / size;
double radian = 0;

54
src/analyzers/analyzerbase.h Executable file → Normal file
View File

@ -1,27 +1,49 @@
// Maintainer: Max Howell <max.howell@methylblue.com>, (C) 2004
// Copyright: See COPYING file that comes with this distribution
/* This file is part of Clementine.
Copyright 2004, Max Howell <max.howell@methylblue.com>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2011, Arnaud Bienner <arnaud.bienner@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
#ifndef ANALYZERBASE_H
#define ANALYZERBASE_H
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Max Howell <max.howell@methylblue.com> 2004
*/
#ifndef ANALYZERS_ANALYZERBASE_H_
#define ANALYZERS_ANALYZERBASE_H_
#ifdef __FreeBSD__
#include <sys/types.h>
#endif
#include "core/fht.h" //stack allocated and convenience
#include "fht.h"
#include "engines/engine_fwd.h"
#include <QPixmap> //stack allocated and convenience
#include <QBasicTimer> //stack allocated
#include <QWidget> //baseclass
#include <vector> //included for convenience
#include <QPixmap>
#include <QBasicTimer>
#include <QWidget>
#include <vector>
#include <QGLWidget> //baseclass
#include <QGLWidget>
#ifdef Q_WS_MACX
#include <OpenGL/gl.h> //included for convenience
#include <OpenGL/glu.h> //included for convenience
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h> //included for convenience
#include <GL/glu.h> //included for convenience
#include <GL/gl.h>
#include <GL/glu.h>
#endif
class QEvent;
@ -53,7 +75,7 @@ class Base : public QWidget {
virtual void framerateChanged() {}
protected:
Base(QWidget*, uint scopeSize = 7);
explicit Base(QWidget*, uint scopeSize = 7);
void hideEvent(QHideEvent*);
void showEvent(QShowEvent*);
@ -86,4 +108,4 @@ void initSin(Scope&, const uint = 6000);
} // END namespace Analyzer
#endif
#endif // ANALYZERS_ANALYZERBASE_H_

View File

@ -1,5 +1,10 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Copyright 2010-2011, David Sansome <davidsansome@gmail.com>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2011-2012, Arnaud Bienner <arnaud.bienner@gmail.com>
Copyright 2013, Vasily Fomin <vasili.fomin@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,6 +25,7 @@
#include "blockanalyzer.h"
#include "boomanalyzer.h"
#include "nyancatanalyzer.h"
#include "rainbowdashanalyzer.h"
#include "sonogram.h"
#include "turbine.h"
#include "core/logging.h"
@ -74,6 +80,7 @@ AnalyzerContainer::AnalyzerContainer(QWidget* parent)
AddAnalyzerType<Sonogram>();
AddAnalyzerType<TurbineAnalyzer>();
AddAnalyzerType<NyanCatAnalyzer>();
AddAnalyzerType<RainbowDashAnalyzer>();
connect(mapper_, SIGNAL(mapped(int)), SLOT(ChangeAnalyzer(int)));
disable_action_ = context_menu_->addAction(tr("No analyzer"), this,

View File

@ -1,5 +1,9 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Copyright 2010, David Sansome <davidsansome@gmail.com>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2011-2012, Arnaud Bienner <arnaud.bienner@gmail.com>
Copyright 2013, Vasily Fomin <vasili.fomin@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,8 +19,8 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANALYZERCONTAINER_H
#define ANALYZERCONTAINER_H
#ifndef ANALYZERS_ANALYZERCONTAINER_H_
#define ANALYZERS_ANALYZERCONTAINER_H_
#include <QWidget>
#include <QMenu>
@ -29,15 +33,14 @@ class AnalyzerContainer : public QWidget {
Q_OBJECT
public:
AnalyzerContainer(QWidget* parent);
explicit AnalyzerContainer(QWidget* parent);
void SetEngine(EngineBase* engine);
void SetActions(QAction* visualisation);
static const char* kSettingsGroup;
static const char* kSettingsFramerate;
signals:
signals:
void WheelEvent(int delta);
protected:
@ -100,4 +103,4 @@ void AnalyzerContainer::AddAnalyzerType() {
actions_ << action;
}
#endif
#endif // ANALYZERS_ANALYZERCONTAINER_H_

View File

@ -1,18 +1,31 @@
//
//
// C++ Implementation: $MODULE$
//
// Description:
//
//
// Author: Mark Kretschmann <markey@web.de>, (C) 2003
//
// Copyright: See COPYING file that comes with this distribution
//
//
/* This file is part of Clementine.
Copyright 2003, Mark Kretschmann <markey@web.de>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Mark Kretschmann <markey@web.de> 2003
*/
#include "baranalyzer.h"
#include <cmath> //log10(), etc.
#include <cmath>
#include <QtDebug>
#include <QPainter>
@ -25,17 +38,17 @@ BarAnalyzer::BarAnalyzer(QWidget* parent) : Analyzer::Base(parent, 8) {
// roof pixmaps don't depend on size() so we do in the ctor
m_bg = parent->palette().color(QPalette::Background);
QColor fg(0xff, 0x50, 0x70);
QColor fg(parent->palette().color(QPalette::Highlight).lighter(150));
double dr = double(m_bg.red() - fg.red()) /
(NUM_ROOFS - 1); //-1 because we start loop below at 0
double dg = double(m_bg.green() - fg.green()) / (NUM_ROOFS - 1);
double db = double(m_bg.blue() - fg.blue()) / (NUM_ROOFS - 1);
double dr = static_cast<double>(m_bg.red() - fg.red()) /
(NUM_ROOFS - 1); // -1 because we start loop below at 0
double dg = static_cast<double>(m_bg.green() - fg.green()) / (NUM_ROOFS - 1);
double db = static_cast<double>(m_bg.blue() - fg.blue()) / (NUM_ROOFS - 1);
for (uint i = 0; i < NUM_ROOFS; ++i) {
m_pixRoof[i] = QPixmap(COLUMN_WIDTH, 1);
m_pixRoof[i].fill(QColor(fg.red() + int(dr * i), fg.green() + int(dg * i),
fg.blue() + int(db * i)));
m_pixRoof[i].fill(QColor(fg.red() + static_cast<int>(dr * i), fg.green() + static_cast<int>(dg * i),
fg.blue() + static_cast<int>(db * i)));
}
}
@ -45,11 +58,11 @@ void BarAnalyzer::resizeEvent(QResizeEvent* e) { init(); }
void BarAnalyzer::init() {
const double MAX_AMPLITUDE = 1.0;
const double F = double(height() - 2) / (log10(255) * MAX_AMPLITUDE);
const double F = static_cast<double>(height() - 2) / (log10(255) * MAX_AMPLITUDE);
BAND_COUNT = width() / 5;
MAX_DOWN = int(0 - (qMax(1, height() / 50)));
MAX_UP = int(qMax(1, height() / 25));
MAX_DOWN = static_cast<int>(0 - (qMax(1, height() / 50)));
MAX_UP = static_cast<int>(qMax(1, height() / 25));
barVector.resize(BAND_COUNT, 0);
roofVector.resize(BAND_COUNT, height() - 5);
@ -60,7 +73,7 @@ void BarAnalyzer::init() {
// generate a list of values that express amplitudes in range 0-MAX_AMP as
// ints from 0-height() on log scale
for (uint x = 0; x < 256; ++x) {
m_lvlMapper[x] = uint(F * log10(x + 1));
m_lvlMapper[x] = static_cast<uint>(F * log10(x + 1));
}
m_pixBarGradient = QPixmap(height() * COLUMN_WIDTH, height());
@ -69,14 +82,16 @@ void BarAnalyzer::init() {
canvas_.fill(palette().color(QPalette::Background));
QPainter p(&m_pixBarGradient);
for (int x = 0, r = 0x40, g = 0x30, b = 0xff, r2 = 255 - r; x < height();
QColor rgb(palette().color(QPalette::Highlight));
for (int x = 0, r = rgb.red(), g = rgb.green(), b = rgb.blue(), r2 = 255 - r; x < height();
++x) {
for (int y = x; y > 0; --y) {
const double fraction = (double)y / height();
const double fraction = static_cast<double>(y) / height();
// p.setPen( QColor( r + (int)(r2 * fraction), g, b - (int)(255 *
// fraction) ) );
p.setPen(QColor(r + (int)(r2 * fraction), g, b));
p.setPen(QColor(r + static_cast<int>(r2 * fraction), g, b));
p.drawLine(x * COLUMN_WIDTH, height() - y, (x + 1) * COLUMN_WIDTH,
height() - y);
}
@ -100,8 +115,8 @@ void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) {
for (uint i = 0, x = 0, y2; i < v.size(); ++i, x += COLUMN_WIDTH + 1) {
// assign pre[log10]'d value
y2 = uint(v[i] *
256); // 256 will be optimised to a bitshift //no, it's a float
y2 = static_cast<uint>(v[i] *
256); // 256 will be optimised to a bitshift //no, it's a float
y2 = m_lvlMapper[(y2 > 255) ? 255 : y2]; // lvlMapper is array of ints with
// values 0 to height()
@ -122,8 +137,8 @@ void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) {
MAX_DOWN)
y2 = barVector[i] + MAX_DOWN;
if ((int)y2 > roofVector[i]) {
roofVector[i] = (int)y2;
if (static_cast<int>(y2) > roofVector[i]) {
roofVector[i] = static_cast<int>(y2);
roofVelocityVector[i] = 1;
}
@ -160,8 +175,9 @@ void BarAnalyzer::analyze(QPainter& p, const Scope& s, bool new_frame) {
if (roofVector[i] < 0) {
roofVector[i] = 0; // not strictly necessary
roofVelocityVector[i] = 0;
} else
} else {
++roofVelocityVector[i];
}
}
}

View File

@ -1,10 +1,31 @@
// Maintainer: Max Howell <max.howell@methylblue.com>
// Authors: Mark Kretschmann & Max Howell (C) 2003-4
// Copyright: See COPYING file that comes with this distribution
//
/* This file is part of Clementine.
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
Copyright 2005, Mark Kretschmann <markey@web.de>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof A. Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
#ifndef BARANALYZER_H
#define BARANALYZER_H
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Max Howell <max.howell@methylblue.com> 2003-2005
* Original Author: Mark Kretschmann <markey@web.de> 2005
*/
#ifndef ANALYZERS_BARANALYZER_H_
#define ANALYZERS_BARANALYZER_H_
#include "analyzerbase.h"
@ -12,6 +33,7 @@ typedef std::vector<uint> aroofMemVec;
class BarAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BarAnalyzer(QWidget*);
@ -57,4 +79,4 @@ class BarAnalyzer : public Analyzer::Base {
QColor m_bg;
};
#endif
#endif // ANALYZERS_BARANALYZER_H_

View File

@ -1,7 +1,28 @@
// Author: Max Howell <max.howell@methylblue.com>, (C) 2003-5
// Mark Kretschmann <markey@web.de>, (C) 2005
// Copyright: See COPYING file that comes with this distribution
//
/* This file is part of Clementine.
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
Copyright 2005, Mark Kretschmann <markey@web.de>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Max Howell <max.howell@methylblue.com> 2003-2005
* Original Author: Mark Kretschmann <markey@web.de> 2005
*/
#include "blockanalyzer.h"
@ -24,28 +45,19 @@ const char* BlockAnalyzer::kName =
BlockAnalyzer::BlockAnalyzer(QWidget* parent)
: Analyzer::Base(parent, 9),
m_columns(0) // uint
,
m_rows(0) // uint
,
m_y(0) // uint
,
m_barPixmap(1, 1) // null qpixmaps cause crashes
,
m_columns(0),
m_rows(0),
m_y(0),
m_barPixmap(1, 1),
m_topBarPixmap(WIDTH, HEIGHT),
m_scope(MIN_COLUMNS) // Scope
,
m_store(1 << 8, 0) // vector<uint>
,
m_fade_bars(FADE_SIZE) // vector<QPixmap>
,
m_fade_pos(1 << 8, 50) // vector<uint>
,
m_fade_intensity(1 << 8, 32) // vector<uint>
{
m_scope(MIN_COLUMNS),
m_store(1 << 8, 0),
m_fade_bars(FADE_SIZE),
m_fade_pos(1 << 8, 50),
m_fade_intensity(1 << 8, 32) {
setMinimumSize(MIN_COLUMNS * (WIDTH + 1) - 1,
MIN_ROWS * (HEIGHT + 1) -
1); //-1 is padding, no drawing takes place there
MIN_ROWS * (HEIGHT + 1) - 1);
// -1 is padding, no drawing takes place there
setMaximumWidth(MAX_COLUMNS * (WIDTH + 1) - 1);
// mxcl says null pixmaps cause crashes, so let's play it safe
@ -63,9 +75,9 @@ void BlockAnalyzer::resizeEvent(QResizeEvent* e) {
const uint oldRows = m_rows;
// all is explained in analyze()..
//+1 to counter -1 in maxSizes, trust me we need this!
m_columns = qMax(uint(double(width() + 1) / (WIDTH + 1)), MAX_COLUMNS);
m_rows = uint(double(height() + 1) / (HEIGHT + 1));
// +1 to counter -1 in maxSizes, trust me we need this!
m_columns = qMax(static_cast<uint>(static_cast<double>(width() + 1) / (WIDTH + 1)), MAX_COLUMNS);
m_rows = static_cast<uint>(static_cast<double>(height() + 1) / (HEIGHT + 1));
// this is the y-offset for drawing from the top of the widget
m_y = (height() - (m_rows * (HEIGHT + 1)) + 2) / 2;
@ -103,15 +115,14 @@ void BlockAnalyzer::determineStep() {
// the fall time of 30 is too slow on framerates above 50fps
const double fallTime = timeout() < 20 ? 20 * m_rows : 30 * m_rows;
m_step = double(m_rows * timeout()) / fallTime;
m_step = static_cast<double>(m_rows * timeout()) / fallTime;
}
void BlockAnalyzer::framerateChanged() { // virtual
determineStep();
}
void BlockAnalyzer::transform(Analyzer::Scope& s) // pure virtual
{
void BlockAnalyzer::transform(Analyzer::Scope& s) {
for (uint x = 0; x < s.size(); ++x) s[x] *= 2;
float* front = static_cast<float*>(&s.front());
@ -157,12 +168,12 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
for (uint y, x = 0; x < m_scope.size(); ++x) {
// determine y
for (y = 0; m_scope[x] < m_yscale[y]; ++y)
;
continue;
// this is opposite to what you'd think, higher than y
// means the bar is lower than y (physically)
if ((float)y > m_store[x])
y = int(m_store[x] += m_step);
if (static_cast<float>(y) > m_store[x])
y = static_cast<int>(m_store[x] += m_step);
else
m_store[x] = y;
@ -191,8 +202,9 @@ void BlockAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
}
for (uint x = 0; x < m_store.size(); ++x)
canvas_painter.drawPixmap(
x * (WIDTH + 1), int(m_store[x]) * (HEIGHT + 1) + m_y, m_topBarPixmap);
canvas_painter.drawPixmap(x * (WIDTH + 1),
static_cast<int>(m_store[x]) * (HEIGHT + 1) + m_y,
m_topBarPixmap);
p.drawPixmap(0, 0, canvas_);
}
@ -231,7 +243,7 @@ static inline void adjustToLimits(int& b, int& f, uint& amount) {
QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) {
class OutputOnExit {
public:
OutputOnExit(const QColor& color) : c(color) {}
explicit OutputOnExit(const QColor& color) : c(color) {}
~OutputOnExit() {
int h, s, v;
c.getHsv(&h, &s, &v);
@ -241,14 +253,6 @@ QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) {
const QColor& c;
};
// hack so I don't have to cast everywhere
#define amount static_cast<int>(_amount)
// #define STAMP debug() << (QValueList<int>() << fh << fs << fv) << endl;
// #define STAMP1( string ) debug() << string << ": " <<
// (QValueList<int>() << fh << fs << fv) << endl;
// #define STAMP2( string, value ) debug() << string << "=" << value << ":
// " << (QValueList<int>() << fh << fs << fv) << endl;
OutputOnExit allocateOnTheStack(fg);
int bh, bs, bv;
@ -259,23 +263,17 @@ QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) {
int dv = abs(bv - fv);
// STAMP2( "DV", dv );
// value is the best measure of contrast
// if there is enough difference in value already, return fg unchanged
if (dv > amount) return fg;
if (dv > static_cast<int>(_amount)) return fg;
int ds = abs(bs - fs);
// STAMP2( "DS", ds );
// saturation is good enough too. But not as good. TODO adapt this a little
if (ds > amount) return fg;
if (ds > static_cast<int>(_amount)) return fg;
int dh = abs(bh - fh);
// STAMP2( "DH", dh );
if (dh > 120) {
// a third of the colour wheel automatically guarentees contrast
// but only if the values are high enough and saturations significant enough
@ -283,105 +281,75 @@ QColor ensureContrast(const QColor& bg, const QColor& fg, uint _amount = 150) {
// check the saturation for the two colours is sufficient that hue alone can
// provide sufficient contrast
if (ds > amount / 2 && (bs > 125 && fs > 125))
// STAMP1( "Sufficient saturation difference, and hues are
// compliemtary" );
if (ds > static_cast<int>(_amount) / 2 && (bs > 125 && fs > 125))
return fg;
else if (dv > amount / 2 && (bv > 125 && fv > 125))
// STAMP1( "Sufficient value difference, and hues are
// compliemtary" );
else if (dv > static_cast<int>(_amount) / 2 && (bv > 125 && fv > 125))
return fg;
// STAMP1( "Hues are complimentary but we must modify the value or
// saturation of the contrasting colour" );
// but either the colours are two desaturated, or too dark
// so we need to adjust the system, although not as much
///_amount /= 2;
}
if (fs < 50 && ds < 40) {
// low saturation on a low saturation is sad
const int tmp = 50 - fs;
fs = 50;
if (amount > tmp)
if (static_cast<int>(_amount) > tmp)
_amount -= tmp;
else
_amount = 0;
}
// test that there is available value to honor our contrast requirement
if (255 - dv < amount) {
if (255 - dv < static_cast<int>(_amount)) {
// we have to modify the value and saturation of fg
// adjustToLimits( bv, fv, amount );
// STAMP
// see if we need to adjust the saturation
if (amount > 0) adjustToLimits(bs, fs, _amount);
// STAMP
if (static_cast<int>(_amount) > 0) adjustToLimits(bs, fs, _amount);
// see if we need to adjust the hue
if (amount > 0) fh += amount; // cycles around;
// STAMP
if (static_cast<int>(_amount) > 0) fh += static_cast<int>(_amount); // cycles around;
return QColor::fromHsv(fh, fs, fv);
}
// STAMP
if (fv > bv && bv > static_cast<int>(_amount))
return QColor::fromHsv(fh, fs, bv - static_cast<int>(_amount));
if (fv > bv && bv > amount) return QColor::fromHsv(fh, fs, bv - amount);
if (fv < bv && fv > static_cast<int>(_amount))
return QColor::fromHsv(fh, fs, fv - static_cast<int>(_amount));
// STAMP
if (fv > bv && (255 - fv > static_cast<int>(_amount)))
return QColor::fromHsv(fh, fs, fv + static_cast<int>(_amount));
if (fv < bv && fv > amount) return QColor::fromHsv(fh, fs, fv - amount);
// STAMP
if (fv > bv && (255 - fv > amount))
return QColor::fromHsv(fh, fs, fv + amount);
// STAMP
if (fv < bv && (255 - bv > amount))
return QColor::fromHsv(fh, fs, bv + amount);
// STAMP
// debug() << "Something went wrong!\n";
if (fv < bv && (255 - bv > static_cast<int>(_amount)))
return QColor::fromHsv(fh, fs, bv + static_cast<int>(_amount));
return Qt::blue;
#undef amount
// #undef STAMP
}
void BlockAnalyzer::paletteChange(const QPalette&) // virtual
{
void BlockAnalyzer::paletteChange(const QPalette&) {
const QColor bg = palette().color(QPalette::Background);
const QColor fg = ensureContrast(bg, palette().color(QPalette::Highlight));
m_topBarPixmap.fill(fg);
const double dr = 15 * double(bg.red() - fg.red()) / (m_rows * 16);
const double dg = 15 * double(bg.green() - fg.green()) / (m_rows * 16);
const double db = 15 * double(bg.blue() - fg.blue()) / (m_rows * 16);
const double dr = 15 * static_cast<double>(bg.red() - fg.red()) / (m_rows * 16);
const double dg = 15 * static_cast<double>(bg.green() - fg.green()) / (m_rows * 16);
const double db = 15 * static_cast<double>(bg.blue() - fg.blue()) / (m_rows * 16);
const int r = fg.red(), g = fg.green(), b = fg.blue();
bar()->fill(bg);
QPainter p(bar());
for (int y = 0; (uint)y < m_rows; ++y)
for (int y = 0; static_cast<uint>(y) < m_rows; ++y)
// graduate the fg color
p.fillRect(0, y * (HEIGHT + 1), WIDTH, HEIGHT,
QColor(r + int(dr * y), g + int(dg * y), b + int(db * y)));
QColor(r + static_cast<int>(dr * y), g + static_cast<int>(dg * y),
b + static_cast<int>(db * y)));
{
const QColor bg = palette().color(QPalette::Background).dark(112);
// make a complimentary fadebar colour
// TODO dark is not always correct, dumbo!
// TODO(John Maguire): dark is not always correct, dumbo!
int h, s, v;
palette().color(QPalette::Background).dark(150).getHsv(&h, &s, &v);
const QColor fg(QColor::fromHsv(h + 120, s, v));
@ -395,10 +363,10 @@ void BlockAnalyzer::paletteChange(const QPalette&) // virtual
for (uint y = 0; y < FADE_SIZE; ++y) {
m_fade_bars[y].fill(palette().color(QPalette::Background));
QPainter f(&m_fade_bars[y]);
for (int z = 0; (uint)z < m_rows; ++z) {
for (int z = 0; static_cast<uint>(z) < m_rows; ++z) {
const double Y = 1.0 - (log10(FADE_SIZE - y) / log10(FADE_SIZE));
f.fillRect(0, z * (HEIGHT + 1), WIDTH, HEIGHT,
QColor(r + int(dr * Y), g + int(dg * Y), b + int(db * Y)));
QColor(r + static_cast<int>(dr * Y), g + static_cast<int>(dg * Y), b + static_cast<int>(db * Y)));
}
}
}

View File

@ -1,9 +1,29 @@
// Maintainer: Max Howell <mac.howell@methylblue.com>, (C) 2003-5
// Copyright: See COPYING file that comes with this distribution
//
/* This file is part of Clementine.
Copyright 2003-2005, Max Howell <max.howell@methylblue.com>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof A. Sobiecki <sobkas@gmail.com>
#ifndef BLOCKANALYZER_H
#define BLOCKANALYZER_H
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Max Howell <max.howell@methylblue.com> 2003-2005
*/
#ifndef ANALYZERS_BLOCKANALYZER_H_
#define ANALYZERS_BLOCKANALYZER_H_
#include "analyzerbase.h"
#include <qcolor.h>
@ -12,12 +32,9 @@ class QResizeEvent;
class QMouseEvent;
class QPalette;
/**
* @author Max Howell
*/
class BlockAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BlockAnalyzer(QWidget*);
~BlockAnalyzer();
@ -62,4 +79,4 @@ class BlockAnalyzer : public Analyzer::Base {
float m_step; // rows to fall per frame
};
#endif
#endif // ANALYZERS_BLOCKANALYZER_H_

View File

@ -1,5 +1,26 @@
// Author: Max Howell <max.howell@methylblue.com>, (C) 2004
// Copyright: See COPYING file that comes with this distribution
/* This file is part of Clementine.
Copyright 2004, Max Howell <max.howell@methylblue.com>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Max Howell <max.howell@methylblue.com> 2004
*/
#include "boomanalyzer.h"
#include <cmath>
@ -23,11 +44,11 @@ BoomAnalyzer::BoomAnalyzer(QWidget* parent)
barPixmap(COLUMN_WIDTH, 50) {}
void BoomAnalyzer::changeK_barHeight(int newValue) {
K_barHeight = (double)newValue / 1000;
K_barHeight = static_cast<double>(newValue) / 1000;
}
void BoomAnalyzer::changeF_peakSpeed(int newValue) {
F_peakSpeed = (double)newValue / 1000;
F_peakSpeed = static_cast<double>(newValue) / 1000;
}
void BoomAnalyzer::resizeEvent(QResizeEvent*) { init(); }
@ -36,7 +57,7 @@ void BoomAnalyzer::init() {
const uint HEIGHT = height() - 2;
const double h = 1.2 / HEIGHT;
F = double(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/);
F = static_cast<double>(HEIGHT) / (log10(256) * 1.1 /*<- max. amplitude*/);
barPixmap = QPixmap(COLUMN_WIDTH - 2, HEIGHT);
canvas_ = QPixmap(size());
@ -44,11 +65,11 @@ void BoomAnalyzer::init() {
QPainter p(&barPixmap);
for (uint y = 0; y < HEIGHT; ++y) {
const double F = (double)y * h;
const double F = static_cast<double>(y) * h;
p.setPen(QColor(qMax(0, 255 - int(229.0 * F)),
qMax(0, 255 - int(229.0 * F)),
qMax(0, 255 - int(191.0 * F))));
p.setPen(QColor(qMax(0, 255 - static_cast<int>(229.0 * F)),
qMax(0, 255 - static_cast<int>(229.0 * F)),
qMax(0, 255 - static_cast<int>(191.0 * F))));
p.drawLine(0, y, COLUMN_WIDTH - 2, y);
}
}
@ -94,8 +115,9 @@ void BoomAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
if (h > peak_height[i]) {
peak_height[i] = h;
peak_speed[i] = 0.01;
} else
} else {
goto peak_handling;
}
} else {
if (bar_height[i] > 0.0) {
bar_height[i] -= K_barHeight; // 1.4

View File

@ -1,9 +1,29 @@
// Author: Max Howell <max.howell@methylblue.com>, (C) 2004
// Copyright: See COPYING file that comes with this distribution
//
/* This file is part of Clementine.
Copyright 2004, Max Howell <max.howell@methylblue.com>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
#ifndef BOOMANALYZER_H
#define BOOMANALYZER_H
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Max Howell <max.howell@methylblue.com> 2004
*/
#ifndef ANALYZERS_BOOMANALYZER_H_
#define ANALYZERS_BOOMANALYZER_H_
#include "analyzerbase.h"
@ -13,6 +33,7 @@
class BoomAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE BoomAnalyzer(QWidget*);
@ -42,4 +63,4 @@ class BoomAnalyzer : public Analyzer::Base {
QPixmap canvas_;
};
#endif
#endif // ANALYZERS_BOOMANALYZER_H_

View File

@ -1,22 +1,24 @@
// FHT - Fast Hartley Transform Class
//
// Copyright (C) 2004 Melchior FRANZ - mfranz@kde.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA
//
// $Id$
/* This file is part of Clementine.
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Melchior FRANZ <mfranz@kde.org> 2004
*/
#include <math.h>
#include <string.h>
@ -58,11 +60,11 @@ void FHT::makeCasTable(void) {
}
float* FHT::copy(float* d, float* s) {
return (float*)memcpy(d, s, m_num * sizeof(float));
return static_cast<float*>(memcpy(d, s, m_num * sizeof(float)));
}
float* FHT::clear(float* d) {
return (float*)memset(d, 0, m_num * sizeof(float));
return static_cast<float*>(memset(d, 0, m_num * sizeof(float)));
}
void FHT::scale(float* p, float d) {
@ -77,9 +79,9 @@ void FHT::logSpectrum(float* out, float* p) {
int n = m_num / 2, i, j, k, *r;
if (!m_log) {
m_log = new int[n];
float f = n / log10((double)n);
float f = n / log10(static_cast<double>(n));
for (i = 0, r = m_log; i < n; i++, r++) {
j = int(rint(log10(i + 1.0) * f));
j = static_cast<int>(rint(log10(i + 1.0) * f));
*r = j >= n ? n - 1 : j;
}
}
@ -87,9 +89,9 @@ void FHT::logSpectrum(float* out, float* p) {
*out++ = *p = *p / 100;
for (k = i = 1, r = m_log; i < n; i++) {
j = *r++;
if (i == j)
if (i == j) {
*out++ = p[i];
else {
} else {
float base = p[k - 1];
float step = (p[j] - base) / (j - (k - 1));
for (float corr = 0; k <= j; k++, corr += step) *out++ = base + corr;
@ -108,7 +110,8 @@ void FHT::semiLogSpectrum(float* p) {
void FHT::spectrum(float* p) {
power2(p);
for (int i = 0; i < (m_num / 2); i++, p++) *p = (float)sqrt(*p * .5);
for (int i = 0; i < (m_num / 2); i++, p++)
*p = static_cast<float>(sqrt(*p * .5));
}
void FHT::power(float* p) {

View File

@ -1,25 +1,27 @@
// FHT - Fast Hartley Transform Class
//
// Copyright (C) 2004 Melchior FRANZ - mfranz@kde.org
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA
//
// $Id$
/* This file is part of Clementine.
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
#ifndef FHT_H
#define FHT_H
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Melchior FRANZ <mfranz@kde.org> 2004
*/
#ifndef ANALYZERS_FHT_H_
#define ANALYZERS_FHT_H_
/**
* Implementation of the Hartley Transform after Bracewell's discrete
@ -54,7 +56,7 @@ class FHT {
* should be at least 3. Values of more than 3 need a trigonometry table.
* @see makeCasTable()
*/
FHT(int);
explicit FHT(int);
~FHT();
inline int sizeExp() const { return m_exp2; }
@ -115,4 +117,4 @@ class FHT {
void transform(float*);
};
#endif
#endif // ANALYZERS_FHT_H_

View File

@ -1,19 +1,25 @@
/***************************************************************************
gloscope.cpp - description
-------------------
begin : Jan 17 2004
copyright : (C) 2004 by Adam Pigg
email : adam@piggz.co.uk
***************************************************************************/
/* This file is part of Clementine.
Copyright 2004, Adam Pigg <adam@piggz.co.uk>
Copyright 2009, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Adam Pigg <adam@piggz.co.uk> 2004
*/
#include <config.h>
@ -28,8 +34,6 @@ GLAnalyzer::GLAnalyzer(QWidget* parent)
GLAnalyzer::~GLAnalyzer() {}
// METHODS =====================================================
void GLAnalyzer::analyze(const Scope& s) {
// kdDebug() << "Scope Size: " << s.size() << endl;
/* Scope t(32);
@ -66,16 +70,13 @@ void GLAnalyzer::analyze(const Scope& s) {
mfactor = 20 / peak;
for (uint i = 0; i < 32; i++) {
// kdDebug() << "Scope item " << i << " value: " << s[i] << endl;
// Calculate new horizontal position (x) depending on number of samples
x = -16.0f + i;
// Calculating new vertical position (y) depending on the data passed by
// amarok
y = float(s[i + offset] * mfactor); // This make it kinda dynamically
// resize depending on the data
y = static_cast<float>(s[i + offset] * mfactor); // This make it kinda dynamically
// resize depending on the data
// Some basic bounds checking
if (y > 30)
@ -83,10 +84,10 @@ void GLAnalyzer::analyze(const Scope& s) {
else if (y < 0)
y = 0;
if ((y - m_oldy[i]) < -0.6f) // Going Down Too Much
{
if ((y - m_oldy[i]) < -0.6f) {
y = m_oldy[i] - 0.7f;
}
if (y < 0.0f) {
y = 0.0f;
}
@ -145,9 +146,6 @@ void GLAnalyzer::resizeGL(int w, int h) {
void GLAnalyzer::paintGL() {
glMatrixMode(GL_MODELVIEW);
#if 0
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
#else
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glPushMatrix();

View File

@ -1,32 +1,34 @@
/***************************************************************************
gloscope.h - description
-------------------
begin : Jan 17 2004
copyright : (C) 2004 by Adam Pigg
email : adam@piggz.co.uk
***************************************************************************/
/* This file is part of Clementine.
Copyright 2004, Adam Pigg <adam@piggz.co.uk>
Copyright 2009, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
#ifndef GLOSCOPE_H
#define GLOSCOPE_H
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Adam Pigg <adam@piggz.co.uk> 2004
*/
#ifndef ANALYZERS_GLANALYZER_H_
#define ANALYZERS_GLANALYZER_H_
#include <config.h>
#ifdef HAVE_QGLWIDGET
#include "analyzerbase.h"
/**
*@author piggz
*/
typedef struct {
float level;
uint delay;
@ -46,7 +48,7 @@ class GLAnalyzer : public Analyzer::Base3D {
GLfloat x, y;
public:
GLAnalyzer(QWidget*);
explicit GLAnalyzer(QWidget*);
~GLAnalyzer();
void analyze(const Scope&);
@ -57,4 +59,4 @@ class GLAnalyzer : public Analyzer::Base3D {
};
#endif
#endif
#endif // ANALYZERS_GLANALYZER_H_

View File

@ -1,19 +1,25 @@
/***************************************************************************
glanalyzer2.cpp - description
-------------------
begin : Feb 16 2004
copyright : (C) 2004 by Enrico Ros
email : eros.kde@email.it
***************************************************************************/
/* This file is part of Clementine.
Copyright 2004, Enrico Ros <eros.kde@email.it>
Copyright 2009, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Enrico Ros <eros.kde@email.it> 2004
*/
#include <config.h>
@ -71,7 +77,7 @@ void GLAnalyzer2::resizeGL(int w, int h) {
glOrtho(-10.0f, 10.0f, -10.0f, 10.0f, -5.0f, 5.0f);
// Get the aspect ratio of the screen to draw 'cicular' particles
float ratio = (float)w / (float)h, eqPixH = 60, eqPixW = 80;
float ratio = static_cast<float>(w) / static_cast<float>(h), eqPixH = 60, eqPixW = 80;
if (ratio >= (4.0 / 3.0)) {
unitX = 10.0 / (eqPixH * ratio);
unitY = 10.0 / eqPixH;
@ -83,7 +89,7 @@ void GLAnalyzer2::resizeGL(int w, int h) {
// Get current timestamp.
timeval tv;
gettimeofday(&tv, nullptr);
show.timeStamp = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
show.timeStamp = static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1000000.0;
}
void GLAnalyzer2::paused() { analyze(Scope()); }
@ -103,19 +109,20 @@ void GLAnalyzer2::analyze(const Scope& s) {
for (int i = 0; i < bands; i++) {
float value = s[i];
currentEnergy += value;
currentMeanBand += (float)i * value;
currentMeanBand += static_cast<float>(i) * value;
if (value > maxValue) maxValue = value;
}
frame.silence = currentEnergy < 0.001;
if (!frame.silence) {
frame.meanBand = 100.0 * currentMeanBand / (currentEnergy * bands);
currentEnergy = 100.0 * currentEnergy / (float)bands;
currentEnergy = 100.0 * currentEnergy / static_cast<float>(bands);
frame.dEnergy = currentEnergy - frame.energy;
frame.energy = currentEnergy;
// printf( "%d [%f :: %f ]\t%f \n", bands, frame.energy,
// frame.meanBand, maxValue );
} else
} else {
frame.energy = 0.0;
}
}
// update the frame
@ -126,7 +133,7 @@ void GLAnalyzer2::paintGL() {
// Compute the dT since the last call to paintGL and update timings
timeval tv;
gettimeofday(&tv, nullptr);
double currentTime = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
double currentTime = static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1000000.0;
show.dT = currentTime - show.timeStamp;
show.timeStamp = currentTime;
@ -202,8 +209,9 @@ void GLAnalyzer2::paintGL() {
if (dotTexture) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, dotTexture);
} else
} else {
glDisable(GL_TEXTURE_2D);
}
glLoadIdentity();
// glRotatef( -frame.rotDegrees, 0,0,1 );

View File

@ -1,22 +1,28 @@
/***************************************************************************
glanalyzer2.h - description
-------------------
begin : Feb 16 2004
copyright : (C) 2004 by Enrico Ros
email : eros.kde@email.it
***************************************************************************/
/* This file is part of Clementine.
Copyright 2004, Enrico Ros <eros.kde@email.it>
Copyright 2009, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
#ifndef GLSTARVIEW_H
#define GLSTARVIEW_H
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Enrico Ros <eros.kde@email.it> 2004
*/
#ifndef ANALYZERS_GLANALYZER2_H_
#define ANALYZERS_GLANALYZER2_H_
#include <config.h>
#ifdef HAVE_QGLWIDGET
@ -27,7 +33,7 @@
class GLAnalyzer2 : public Analyzer::Base3D {
public:
GLAnalyzer2(QWidget*);
explicit GLAnalyzer2(QWidget*);
~GLAnalyzer2();
void analyze(const Scope&);
void paused();
@ -68,4 +74,4 @@ class GLAnalyzer2 : public Analyzer::Base3D {
};
#endif
#endif
#endif // ANALYZERS_GLANALYZER2_H_

View File

@ -1,19 +1,25 @@
/***************************************************************************
glanalyzer3.cpp - Bouncing Ballzz
-------------------
begin : Feb 19 2004
copyright : (C) 2004 by Enrico Ros
email : eros.kde@email.it
***************************************************************************/
/* This file is part of Clementine.
Copyright 2004, Enrico Ros <eros.kde@email.it>
Copyright 2009, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Enrico Ros <eros.kde@email.it> 2004
*/
#include <config.h>
@ -40,16 +46,8 @@ class Ball {
vx(0.0),
vy(0.0),
vz(0.0),
mass(0.01 + drand48() / 10.0)
//,color( (float[3]) { 0.0, drand48()*0.5, 0.7 + drand48() * 0.3 } )
{
// this is because GCC < 3.3 can't compile the above line, we aren't sure
// why though
color[0] = 0.0;
color[1] = drand48() * 0.5;
color[2] = 0.7 + drand48() * 0.3;
};
mass(0.01 + drand48() / 10.0),
color((float[3]) { 0.0, drand48()*0.5, 0.7 + drand48() * 0.3 }) {}
float x, y, z, vx, vy, vz, mass;
float color[3];
@ -70,8 +68,8 @@ class Ball {
class Paddle {
public:
Paddle(float xPos)
: onLeft(xPos < 0), mass(1.0), X(xPos), x(xPos), vx(0.0) {};
explicit Paddle(float xPos)
: onLeft(xPos < 0), mass(1.0), X(xPos), x(xPos), vx(0.0) {}
void updatePhysics(float dT) {
x += vx * dT; // posision
@ -165,7 +163,7 @@ void GLAnalyzer3::resizeGL(int w, int h) {
glFrustum(-0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 4.5f);
// Get the aspect ratio of the screen to draw 'circular' particles
float ratio = (float)w / (float)h;
float ratio = static_cast<float>(w) / static_cast<float>(h);
if (ratio >= 1.0) {
unitX = 0.34 / ratio;
unitY = 0.34;
@ -177,7 +175,7 @@ void GLAnalyzer3::resizeGL(int w, int h) {
// Get current timestamp.
timeval tv;
gettimeofday(&tv, nullptr);
show.timeStamp = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
show.timeStamp = static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1000000.0;
}
void GLAnalyzer3::paused() { analyze(Scope()); }
@ -186,7 +184,7 @@ void GLAnalyzer3::analyze(const Scope& s) {
// compute the dTime since the last call
timeval tv;
gettimeofday(&tv, nullptr);
double currentTime = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
double currentTime = static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1000000.0;
show.dT = currentTime - show.timeStamp;
show.timeStamp = currentTime;
@ -200,7 +198,7 @@ void GLAnalyzer3::analyze(const Scope& s) {
currentEnergy += value;
if (value > maxValue) maxValue = value;
}
currentEnergy *= 100.0 / (float)bands;
currentEnergy *= 100.0 / static_cast<float>(bands);
// emulate a peak detector: currentEnergy -> peakEnergy (3tau = 30 seconds)
show.peakEnergy = 1.0 + (show.peakEnergy - 1.0) * exp(-show.dT / 10.0);
if (currentEnergy > show.peakEnergy) show.peakEnergy = currentEnergy;
@ -210,8 +208,9 @@ void GLAnalyzer3::analyze(const Scope& s) {
currentEnergy /= show.peakEnergy;
frame.dEnergy = currentEnergy - frame.energy;
frame.energy = currentEnergy;
} else
} else {
frame.silence = true;
}
// update the frame
updateGL();
@ -259,8 +258,10 @@ void GLAnalyzer3::paintGL() {
if (ballTexture) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, ballTexture);
} else
} else {
glDisable(GL_TEXTURE_2D);
}
glEnable(GL_BLEND);
Ball* ball = balls.first();
for (; ball; ball = balls.next()) {

View File

@ -1,25 +1,31 @@
/***************************************************************************
glanalyzer3.h - description
-------------------
begin : Feb 16 2004
copyright : (C) 2004 by Enrico Ros
email : eros.kde@email.it
***************************************************************************/
/* This file is part of Clementine.
Copyright 2004, Enrico Ros <eros.kde@email.it>
Copyright 2009, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Enrico Ros <eros.kde@email.it> 2004
*/
#include <config.h>
#ifdef HAVE_QGLWIDGET
#ifndef GLBOUNCER_H
#define GLBOUNCER_H
#ifndef ANALYZERS_GLANALYZER3_H_
#define ANALYZERS_GLANALYZER3_H_
#include "analyzerbase.h"
#include <qstring.h>
@ -31,7 +37,7 @@ class Paddle;
class GLAnalyzer3 : public Analyzer::Base3D {
public:
GLAnalyzer3(QWidget*);
explicit GLAnalyzer3(QWidget*);
~GLAnalyzer3();
void analyze(const Scope&);
void paused();
@ -76,4 +82,4 @@ class GLAnalyzer3 : public Analyzer::Base3D {
};
#endif
#endif
#endif // ANALYZERS_GLANALYZER3_H_

View File

@ -1,5 +1,8 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Copyright 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
Copyright 2011-2012, 2014, David Sansome <me@davidsansome.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -40,7 +43,7 @@ NyanCatAnalyzer::NyanCatAnalyzer(QWidget* parent)
px_per_frame_(0),
x_offset_(0),
background_brush_(QColor(0x0f, 0x43, 0x73)) {
memset(history_, 0, arraysize(history_));
memset(history_, 0, sizeof(history_));
for (int i = 0; i < kRainbowBands; ++i) {
colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255),
@ -71,7 +74,7 @@ void NyanCatAnalyzer::resizeEvent(QResizeEvent* e) {
buffer_[1] = QPixmap();
available_rainbow_width_ = width() - kCatWidth + kRainbowOverlap;
px_per_frame_ = float(available_rainbow_width_) / (kHistorySize - 1) + 1;
px_per_frame_ = static_cast<float>(available_rainbow_width_) / (kHistorySize - 1) + 1;
x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_;
}
@ -109,11 +112,11 @@ void NyanCatAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
QPointF* dest = polyline;
float* source = history_;
const float top_of_cat = float(height()) / 2 - float(kCatHeight) / 2;
const float top_of_cat = static_cast<float>(height()) / 2 - static_cast<float>(kCatHeight) / 2;
for (int band = 0; band < kRainbowBands; ++band) {
// Calculate the Y position of this band.
const float y =
float(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + top_of_cat;
static_cast<float>(kCatHeight) / (kRainbowBands + 1) * (band + 0.5) + top_of_cat;
// Add each point in the line.
for (int x = 0; x < kHistorySize; ++x) {

View File

@ -1,5 +1,8 @@
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Copyright 2011, Tyler Rhodes <tyler.s.rhodes@gmail.com>
Copyright 2011-2012, David Sansome <me@davidsansome.com>
Copyright 2011, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,8 +18,8 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef NYANCATANALYZER_H
#define NYANCATANALYZER_H
#ifndef ANALYZERS_NYANCATANALYZER_H_
#define ANALYZERS_NYANCATANALYZER_H_
#include "analyzerbase.h"
@ -102,4 +105,4 @@ class NyanCatAnalyzer : public Analyzer::Base {
QBrush background_brush_;
};
#endif // NYANCATANALYZER_H
#endif // ANALYZERS_NYANCATANALYZER_H_

View File

@ -0,0 +1,180 @@
/* This file is part of Clementine.
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rainbowdashanalyzer.h"
#include <cmath>
#include <QTimerEvent>
#include <QBrush>
#include "core/arraysize.h"
#include "core/logging.h"
using Analyzer::Scope;
const char* RainbowDashAnalyzer::kName = "Rainbow Dash";
const float RainbowDashAnalyzer::kPixelScale = 0.02f;
RainbowDashAnalyzer::RainbowDashAnalyzer(QWidget* parent)
: Analyzer::Base(parent, 9),
dash_(":/rainbowdash.png"),
timer_id_(startTimer(kFrameIntervalMs)),
frame_(0),
current_buffer_(0),
available_rainbow_width_(0),
px_per_frame_(0),
x_offset_(0),
background_brush_(QColor(0x0f, 0x43, 0x73)) {
memset(history_, 0, sizeof(history_));
for (int i = 0; i < kRainbowBands; ++i) {
colors_[i] = QPen(QColor::fromHsv(i * 255 / kRainbowBands, 255, 255),
kRainbowHeight / kRainbowBands, Qt::SolidLine,
Qt::FlatCap, Qt::RoundJoin);
// pow constants computed so that
// | band_scale(0) | ~= .5 and | band_scale(5) | ~= 32
band_scale_[i] =
-std::cos(M_PI * i / (kRainbowBands - 1)) * 0.5 * std::pow(2.3, i);
}
}
void RainbowDashAnalyzer::transform(Scope& s) { m_fht->spectrum(&s.front()); }
void RainbowDashAnalyzer::timerEvent(QTimerEvent* e) {
if (e->timerId() == timer_id_) {
frame_ = (frame_ + 1) % kDashFrameCount;
} else {
Analyzer::Base::timerEvent(e);
}
}
void RainbowDashAnalyzer::resizeEvent(QResizeEvent* e) {
// Invalidate the buffer so it's recreated from scratch in the next paint
// event.
buffer_[0] = QPixmap();
buffer_[1] = QPixmap();
available_rainbow_width_ = width() - kDashWidth + kRainbowOverlap;
px_per_frame_ = static_cast<float>(available_rainbow_width_) / (kHistorySize - 1) + 1;
x_offset_ = px_per_frame_ * (kHistorySize - 1) - available_rainbow_width_;
}
void RainbowDashAnalyzer::analyze(QPainter& p, const Analyzer::Scope& s,
bool new_frame) {
// Discard the second half of the transform
const int scope_size = s.size() / 2;
if ((new_frame && is_playing_) ||
(buffer_[0].isNull() && buffer_[1].isNull())) {
// Transform the music into rainbows!
for (int band = 0; band < kRainbowBands; ++band) {
float* band_start = history_ + band * kHistorySize;
// Move the history of each band across by 1 frame.
memmove(band_start, band_start + 1, (kHistorySize - 1) * sizeof(float));
}
// Now accumulate the scope data into each band. Should maybe use a series
// of band pass filters for this, so bands can leak into neighbouring bands,
// but for now it's a series of separate square filters.
const int samples_per_band = scope_size / kRainbowBands;
int sample = 0;
for (int band = 0; band < kRainbowBands; ++band) {
float accumulator = 0.0;
for (int i = 0; i < samples_per_band; ++i) {
accumulator += s[sample++];
}
history_[(band + 1) * kHistorySize - 1] = accumulator * band_scale_[band];
}
// Create polylines for the rainbows.
QPointF polyline[kRainbowBands * kHistorySize];
QPointF* dest = polyline;
float* source = history_;
const float top_of_Dash = static_cast<float>(height()) / 2 - static_cast<float>(kRainbowHeight) / 2;
for (int band = 0; band < kRainbowBands; ++band) {
// Calculate the Y position of this band.
const float y =
static_cast<float>(kRainbowHeight) / (kRainbowBands + 1) * (band + 0.5) +
top_of_Dash;
// Add each point in the line.
for (int x = 0; x < kHistorySize; ++x) {
*dest = QPointF(px_per_frame_ * x, y + *source * kPixelScale);
++dest;
++source;
}
}
// Do we have to draw the whole rainbow into the buffer?
if (buffer_[0].isNull()) {
for (int i = 0; i < 2; ++i) {
buffer_[i] = QPixmap(QSize(width() + x_offset_, height()));
buffer_[i].fill(background_brush_.color());
}
current_buffer_ = 0;
QPainter buffer_painter(&buffer_[0]);
buffer_painter.setRenderHint(QPainter::Antialiasing);
for (int band = kRainbowBands - 1; band >= 0; --band) {
buffer_painter.setPen(colors_[band]);
buffer_painter.drawPolyline(&polyline[band * kHistorySize],
kHistorySize);
buffer_painter.drawPolyline(&polyline[band * kHistorySize],
kHistorySize);
}
} else {
const int last_buffer = current_buffer_;
current_buffer_ = (current_buffer_ + 1) % 2;
// We can just shuffle the buffer along a bit and draw the new frame's
// data.
QPainter buffer_painter(&buffer_[current_buffer_]);
buffer_painter.setRenderHint(QPainter::Antialiasing);
buffer_painter.drawPixmap(
0, 0, buffer_[last_buffer], px_per_frame_, 0,
x_offset_ + available_rainbow_width_ - px_per_frame_, 0);
buffer_painter.fillRect(
x_offset_ + available_rainbow_width_ - px_per_frame_, 0,
kDashWidth - kRainbowOverlap + px_per_frame_, height(),
background_brush_);
for (int band = kRainbowBands - 1; band >= 0; --band) {
buffer_painter.setPen(colors_[band]);
buffer_painter.drawPolyline(&polyline[(band + 1) * kHistorySize - 3],
3);
}
}
}
// Draw the buffer on to the widget
p.drawPixmap(0, 0, buffer_[current_buffer_], x_offset_, 0, 0, 0);
if (!is_playing_) {
// Ssshhh!
p.drawPixmap(SleepingDashDestRect(), dash_, SleepingDashSourceRect());
} else {
p.drawPixmap(DashDestRect(), dash_, DashSourceRect());
}
}

View File

@ -0,0 +1,108 @@
/* This file is part of Clementine.
Copyright 2014, Alibek Omarov <a1ba.omarov@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANALYZERS_RAINBOWDASHANALYZER_H_
#define ANALYZERS_RAINBOWDASHANALYZER_H_
#include "analyzerbase.h"
#include <QDateTime>
class RainbowDashAnalyzer : public Analyzer::Base {
Q_OBJECT
public:
Q_INVOKABLE RainbowDashAnalyzer(QWidget* parent);
static const char* kName;
protected:
void transform(Analyzer::Scope&);
void analyze(QPainter& p, const Analyzer::Scope&, bool new_frame);
void timerEvent(QTimerEvent* e);
void resizeEvent(QResizeEvent* e);
private:
static const int kDashHeight = 33;
static const int kDashWidth = 53;
static const int kRainbowHeight = 16;
static const int kDashFrameCount = 16;
static const int kRainbowOverlap = 15;
static const int kSleepingDashHeight = 33;
static const int kHistorySize = 128;
static const int kRainbowBands = 6;
static const float kPixelScale;
static const int kFrameIntervalMs = 150;
private:
inline QRect DashSourceRect() const {
return QRect(0, kDashHeight * frame_, kDashWidth, kDashHeight);
}
inline QRect SleepingDashSourceRect() const {
return QRect(0, kDashHeight * kDashFrameCount, kDashWidth,
kSleepingDashHeight);
}
inline QRect DashDestRect() const {
return QRect(width() - kDashWidth, (height() - kDashHeight) / 2, kDashWidth,
kDashHeight);
}
inline QRect SleepingDashDestRect() const {
return QRect(width() - kDashWidth, (height() - kSleepingDashHeight) / 2,
kDashWidth, kSleepingDashHeight);
}
private:
// "constants" that get initialised in the constructor
float band_scale_[kRainbowBands];
QPen colors_[kRainbowBands];
QPixmap dash_;
// For the animation
int timer_id_;
int frame_;
// The y positions of each point on the rainbow.
float history_[kHistorySize * kRainbowBands];
// A cache of the last frame's rainbow, so it can be used in the next frame.
QPixmap buffer_[2];
int current_buffer_;
// Geometry information that's updated on resize:
// The width of the widget minus the space for the pony
int available_rainbow_width_;
// X spacing between each point in the polyline.
int px_per_frame_;
// Amount the buffer_ is shifted to the left (off the edge of the widget) to
// make the rainbow extend from 0 to available_rainbow_width_.
int x_offset_;
QBrush background_brush_;
};
#endif // ANALYZERS_RAINBOWDASHANALYZER_H_

View File

@ -1,15 +1,26 @@
//
//
// C++ Implementation: Sonogram
//
// Description:
//
//
// Author: Melchior FRANZ <mfranz@kde.org>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//
/* This file is part of Clementine.
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2010, 2014, John Maguire <john.maguire@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Melchior FRANZ <mfranz@kde.org> 2004
*/
#include "sonogram.h"
@ -53,9 +64,9 @@ void Sonogram::analyze(QPainter& p, const Scope& s, bool new_frame) {
if (it >= end || *it < .005)
c = palette().color(QPalette::Background);
else if (*it < .05)
c.setHsv(95, 255, 255 - int(*it * 4000.0));
c.setHsv(95, 255, 255 - static_cast<int>(*it * 4000.0));
else if (*it < 1.0)
c.setHsv(95 - int(*it * 90.0), 255, 255);
c.setHsv(95 - static_cast<int>(*it * 90.0), 255, 255);
else
c = Qt::red;

View File

@ -1,18 +1,28 @@
//
//
// C++ Interface: Sonogram
//
// Description:
//
//
// Author: Melchior FRANZ <mfranz@kde.org>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//
/* This file is part of Clementine.
Copyright 2004, Melchior FRANZ <mfranz@kde.org>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
#ifndef SONOGRAM_H
#define SONOGRAM_H
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Melchior FRANZ <mfranz@kde.org> 2004
*/
#ifndef ANALYZERS_SONOGRAM_H_
#define ANALYZERS_SONOGRAM_H_
#include "analyzerbase.h"
@ -37,4 +47,4 @@ class Sonogram : public Analyzer::Base {
QPixmap canvas_;
};
#endif
#endif // ANALYZERS_SONOGRAM_H_

View File

@ -1,11 +1,28 @@
//
// Amarok BarAnalyzer 3 - Jet Turbine: Symmetric version of analyzer 1
//
// Author: Stanislav Karchebny <berkus@users.sf.net>, (C) 2003
// Max Howell (I modified it to use boom analyzer code)
//
// Copyright: like rest of Amarok
//
/* This file is part of Clementine.
Copyright 2003, Stanislav Karchebny <berkus@users.sf.net>
Copyright 2003, Max Howell <max.howell@methylblue.com>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2014, Mark Furneaux <mark@romaco.ca>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Stanislav Karchebny <berkus@users.sf.net> 2003
* Original Author: Max Howell <max.howell@methylblue.com> 2003
*/
#include <cmath>
#include <QPainter>
@ -41,8 +58,9 @@ void TurbineAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
if (h > peak_height[i]) {
peak_height[i] = h;
peak_speed[i] = 0.01;
} else
} else {
goto peak_handling;
}
} else {
if (bar_height[i] > 0.0) {
bar_height[i] -= K_barHeight; // 1.4
@ -60,15 +78,16 @@ void TurbineAnalyzer::analyze(QPainter& p, const Scope& scope, bool new_frame) {
}
}
y = hd2 - uint(bar_height[i]);
y = hd2 - static_cast<uint>(bar_height[i]);
canvas_painter.drawPixmap(x + 1, y, barPixmap, 0, y, -1, -1);
canvas_painter.drawPixmap(x + 1, hd2, barPixmap, 0, int(bar_height[i]), -1,
-1);
canvas_painter.drawPixmap(x + 1, hd2, barPixmap, 0,
static_cast<int>(bar_height[i]),
-1, -1);
canvas_painter.setPen(palette().color(QPalette::Highlight));
if (bar_height[i] > 0)
canvas_painter.drawRect(x, y, COLUMN_WIDTH - 1,
(int)bar_height[i] * 2 - 1);
static_cast<int>(bar_height[i]) * 2 - 1);
const uint x2 = x + COLUMN_WIDTH - 1;
canvas_painter.setPen(palette().color(QPalette::Base));

View File

@ -1,13 +1,28 @@
//
// Amarok BarAnalyzer 3 - Jet Turbine: Symmetric version of analyzer 1
//
// Author: Stanislav Karchebny <berkus@users.sf.net>, (C) 2003
//
// Copyright: like rest of Amarok
//
/* This file is part of Clementine.
Copyright 2003, Stanislav Karchebny <berkus@users.sf.net>
Copyright 2009-2010, David Sansome <davidsansome@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
#ifndef ANALYZER_TURBINE_H
#define ANALYZER_TURBINE_H
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
/* Original Author: Stanislav Karchebny <berkus@users.sf.net> 2003
*/
#ifndef ANALYZERS_TURBINE_H_
#define ANALYZERS_TURBINE_H_
#include "boomanalyzer.h"
@ -21,4 +36,4 @@ class TurbineAnalyzer : public BoomAnalyzer {
static const char* kName;
};
#endif
#endif // ANALYZERS_TURBINE_H_

View File

@ -36,6 +36,7 @@
#cmakedefine HAVE_LIBPULSE
#cmakedefine HAVE_MOODBAR
#cmakedefine HAVE_QCA
#cmakedefine HAVE_SEAFILE
#cmakedefine HAVE_SKYDRIVE
#cmakedefine HAVE_SPARKLE
#cmakedefine HAVE_SPOTIFY_DOWNLOADER
@ -44,5 +45,6 @@
#cmakedefine TAGLIB_HAS_OPUS
#cmakedefine USE_INSTALL_PREFIX
#cmakedefine USE_SYSTEM_PROJECTM
#cmakedefine USE_SYSTEM_SHA2
#endif // CONFIG_H_IN

View File

@ -1,5 +1,7 @@
/* This file is part of Clementine.
Copyright 2012, David Sansome <me@davidsansome.com>
Copyright 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,7 @@
/* This file is part of Clementine.
Copyright 2012, David Sansome <me@davidsansome.com>
Copyright 2012, Arnaud Bienner <arnaud.bienner@gmail.com>
Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
Copyright 2014, John Maguire <john.maguire@gmail.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -15,15 +17,15 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef APPEARANCE_H
#define APPEARANCE_H
#ifndef CORE_APPEARANCE_H_
#define CORE_APPEARANCE_H_
#include <QColor>
#include <QPalette>
class Appearance : public QObject {
public:
Appearance(QObject* parent = nullptr);
explicit Appearance(QObject* parent = nullptr);
// Load the user preferred theme, which could the default system theme or a
// custom set of colors that user has chosen
void LoadUserTheme();
@ -42,4 +44,4 @@ class Appearance : public QObject {
QColor background_color_;
};
#endif // APPEARANCE_H
#endif // CORE_APPEARANCE_H_

Some files were not shown because too many files have changed in this diff Show More