parent
							
								
									6480ebadde
								
							
						
					
					
						commit
						d51bdd6b6a
					
				@ -0,0 +1,232 @@ | 
				
			||||
//
 | 
				
			||||
// Created by frank on 2021/8/16.
 | 
				
			||||
//
 | 
				
			||||
 | 
				
			||||
#include "execute_fft.h" | 
				
			||||
 | 
				
			||||
#include <android/log.h> | 
				
			||||
#define LOG_TAG "execute_fft" | 
				
			||||
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \ | 
				
			||||
                   __VA_ARGS__)) | 
				
			||||
 | 
				
			||||
#define SPECTRUM_WIDTH 4.f | 
				
			||||
#define NB_BANDS 20 | 
				
			||||
#define ROTATION_INCREMENT .1f | 
				
			||||
#define BAR_DECREMENT .075f | 
				
			||||
#define ROTATION_MAX 20 | 
				
			||||
 | 
				
			||||
static inline void block_CopyProperties(block_t *dst, const block_t *src) | 
				
			||||
{ | 
				
			||||
    dst->i_dts        = src->i_dts; | 
				
			||||
    dst->i_pts        = src->i_pts; | 
				
			||||
    dst->i_flags      = src->i_flags; | 
				
			||||
    dst->i_length     = src->i_length; | 
				
			||||
    dst->i_nb_samples = src->i_nb_samples; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static inline block_t *block_Duplicate(const block_t *p_block) | 
				
			||||
{ | 
				
			||||
//    block_t *p_dup = block_Alloc(p_block->i_buffer);//TODO
 | 
				
			||||
    block_t *p_dup = (block_t*) malloc(sizeof(block_t)); | 
				
			||||
    if(p_dup == NULL) return NULL; | 
				
			||||
    p_dup->i_buffer = p_block->i_buffer; | 
				
			||||
    p_dup->p_buffer = (uint8_t*) malloc(p_block->i_buffer);//TODO
 | 
				
			||||
 | 
				
			||||
    block_CopyProperties(p_dup, p_block); | 
				
			||||
    memcpy(p_dup->p_buffer, p_block->p_buffer, p_block->i_buffer); | 
				
			||||
 | 
				
			||||
    return p_dup; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*static*/ int Open(filter_sys_t *p_sys) | 
				
			||||
{ | 
				
			||||
    if (p_sys == NULL) | 
				
			||||
        return VLC_ENOMEM; | 
				
			||||
 | 
				
			||||
    /* Create the object for the thread */ | 
				
			||||
    p_sys->i_channels = 2;//TODO
 | 
				
			||||
    p_sys->i_prev_nb_samples = 0; | 
				
			||||
    p_sys->p_prev_s16_buff = NULL; | 
				
			||||
 | 
				
			||||
    p_sys->f_rotationAngle = 0; | 
				
			||||
    p_sys->f_rotationIncrement = ROTATION_INCREMENT; | 
				
			||||
 | 
				
			||||
    window_param *w_param = (window_param*) malloc(sizeof(window_param)); | 
				
			||||
    p_sys->wind_param = *w_param;//TODO
 | 
				
			||||
 | 
				
			||||
    /* Fetch the FFT window parameters */ | 
				
			||||
    window_get_param(/*VLC_OBJECT( p_filter )*/NULL, &p_sys->wind_param);//TODO
 | 
				
			||||
 | 
				
			||||
    /* Create the FIFO for the audio data. */ | 
				
			||||
    vlc_queue_Init(&p_sys->queue, offsetof (block_t, p_next)); | 
				
			||||
    p_sys->dead = false; | 
				
			||||
 | 
				
			||||
    /* Create the thread */ | 
				
			||||
//    if (vlc_clone(&p_sys->thread, Thread, p_filter,
 | 
				
			||||
//                  VLC_THREAD_PRIORITY_VIDEO)) {
 | 
				
			||||
//        return VLC_ENOMEM;
 | 
				
			||||
//    }
 | 
				
			||||
 | 
				
			||||
    pthread_create (&p_sys->thread, NULL, Thread, p_sys); | 
				
			||||
 | 
				
			||||
    return VLC_SUCCESS; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*static*/ block_t *filter_audio(filter_sys_t *p_sys, block_t *p_in_buf) | 
				
			||||
{ | 
				
			||||
    vlc_queue_Enqueue(&p_sys->queue, block_Duplicate(p_in_buf)); | 
				
			||||
    return p_in_buf; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*static*/ void Close(filter_sys_t *p_filter) | 
				
			||||
{ | 
				
			||||
    filter_sys_t *p_sys = p_filter; | 
				
			||||
 | 
				
			||||
    /* Terminate the thread. */ | 
				
			||||
    vlc_queue_Kill(&p_sys->queue, &p_sys->dead); | 
				
			||||
//    vlc_join(p_sys->thread, NULL);
 | 
				
			||||
    pthread_join(p_sys->thread, NULL); | 
				
			||||
 | 
				
			||||
    free(p_sys->p_prev_s16_buff); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static void *Thread(void *p_data) | 
				
			||||
{ | 
				
			||||
    filter_sys_t *p_sys = (filter_sys_t*)p_data; | 
				
			||||
    block_t *block; | 
				
			||||
 | 
				
			||||
    float height[NB_BANDS] = {0}; | 
				
			||||
    LOGE("start FFT thread..."); | 
				
			||||
    while ((block = vlc_queue_DequeueKillable(&p_sys->queue, &p_sys->dead))) | 
				
			||||
    { | 
				
			||||
        LOGE("running FFT transform..."); | 
				
			||||
        unsigned win_width, win_height; | 
				
			||||
 | 
				
			||||
        /* Horizontal scale for 20-band equalizer */ | 
				
			||||
        const unsigned xscale[] = {0,1,2,3,4,5,6,7,8,11,15,20,27, | 
				
			||||
                                   36,47,62,82,107,141,184,255}; | 
				
			||||
 | 
				
			||||
        fft_state *p_state = NULL; /* internal FFT data */ | 
				
			||||
        DEFINE_WIND_CONTEXT(wind_ctx); /* internal window data */ | 
				
			||||
 | 
				
			||||
        unsigned i, j; | 
				
			||||
        float p_output[FFT_BUFFER_SIZE];           /* Raw FFT Result  */ | 
				
			||||
        int16_t p_buffer1[FFT_BUFFER_SIZE];        /* Buffer on which we perform
 | 
				
			||||
                                                      the FFT (first channel) */ | 
				
			||||
        int16_t p_dest[FFT_BUFFER_SIZE];           /* Adapted FFT result */ | 
				
			||||
        float *p_buffl = (float*)block->p_buffer;  /* Original buffer */ | 
				
			||||
 | 
				
			||||
        int16_t  *p_buffs;                         /* int16_t converted buffer */ | 
				
			||||
        int16_t  *p_s16_buff;                      /* int16_t converted buffer */ | 
				
			||||
 | 
				
			||||
        if (!block->i_nb_samples) { | 
				
			||||
            LOGE("no samples yet..."); | 
				
			||||
            goto release; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        /* Allocate the buffer only if the number of samples change */ | 
				
			||||
        if (block->i_nb_samples != p_sys->i_prev_nb_samples) | 
				
			||||
        { | 
				
			||||
            free(p_sys->p_prev_s16_buff); | 
				
			||||
            p_sys->p_prev_s16_buff = malloc(block->i_nb_samples * | 
				
			||||
                                            p_sys->i_channels * | 
				
			||||
                                            sizeof(int16_t)); | 
				
			||||
            if (!p_sys->p_prev_s16_buff) | 
				
			||||
                goto release; | 
				
			||||
            p_sys->i_prev_nb_samples = block->i_nb_samples; | 
				
			||||
        } | 
				
			||||
        p_buffs = p_s16_buff = p_sys->p_prev_s16_buff; | 
				
			||||
 | 
				
			||||
        /* Convert the buffer to int16_t */ | 
				
			||||
        for (i = block->i_nb_samples * p_sys->i_channels; i--;) | 
				
			||||
        { | 
				
			||||
            union {float f; int32_t i;} u; | 
				
			||||
 | 
				
			||||
            u.f = *p_buffl + 384.f; | 
				
			||||
            if (u.i > 0x43c07fff) | 
				
			||||
                *p_buffs = 32767; | 
				
			||||
            else if (u.i < 0x43bf8000) | 
				
			||||
                *p_buffs = -32768; | 
				
			||||
            else | 
				
			||||
                *p_buffs = u.i - 0x43c00000; | 
				
			||||
 | 
				
			||||
            p_buffl++; p_buffs++; | 
				
			||||
        } | 
				
			||||
        p_state = visual_fft_init(); | 
				
			||||
        if (!p_state) | 
				
			||||
        { | 
				
			||||
            LOGE("unable to initialize FFT transform..."); | 
				
			||||
            goto release; | 
				
			||||
        } | 
				
			||||
        if (!window_init(FFT_BUFFER_SIZE, &p_sys->wind_param, &wind_ctx)) | 
				
			||||
        { | 
				
			||||
            LOGE("unable to initialize FFT window..."); | 
				
			||||
            goto release; | 
				
			||||
        } | 
				
			||||
        p_buffs = p_s16_buff; | 
				
			||||
        for (i = 0 ; i < FFT_BUFFER_SIZE; i++) | 
				
			||||
        { | 
				
			||||
            p_output[i] = 0; | 
				
			||||
            p_buffer1[i] = *p_buffs; | 
				
			||||
 | 
				
			||||
            p_buffs += p_sys->i_channels; | 
				
			||||
            if (p_buffs >= &p_s16_buff[block->i_nb_samples * p_sys->i_channels]) | 
				
			||||
                p_buffs = p_s16_buff; | 
				
			||||
        } | 
				
			||||
        window_scale_in_place (p_buffer1, &wind_ctx); | 
				
			||||
        fft_perform (p_buffer1, p_output, p_state); | 
				
			||||
 | 
				
			||||
        for (i = 0; i< FFT_BUFFER_SIZE; ++i) | 
				
			||||
            p_dest[i] = p_output[i] *  (2 ^ 16) | 
				
			||||
                        / ((FFT_BUFFER_SIZE / 2 * 32768) ^ 2); | 
				
			||||
 | 
				
			||||
        for (i = 0 ; i < NB_BANDS; i++) | 
				
			||||
        { | 
				
			||||
            /* Decrease the previous size of the bar. */ | 
				
			||||
            height[i] -= BAR_DECREMENT; | 
				
			||||
            if (height[i] < 0) | 
				
			||||
                height[i] = 0; | 
				
			||||
 | 
				
			||||
            int y = 0; | 
				
			||||
            /* We search the maximum on one scale
 | 
				
			||||
               to determine the current size of the bar. */ | 
				
			||||
            for (j = xscale[i]; j < xscale[i + 1]; j++) | 
				
			||||
            { | 
				
			||||
                if (p_dest[j] > y) | 
				
			||||
                    y = p_dest[j]; | 
				
			||||
            } | 
				
			||||
            /* Calculate the height of the bar */ | 
				
			||||
            float new_height = y != 0 ? logf(y) * 0.4f : 0; | 
				
			||||
            height[i] = new_height > height[i] | 
				
			||||
                        ? new_height : height[i]; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        /* Determine the camera rotation angle. */ | 
				
			||||
        p_sys->f_rotationAngle += p_sys->f_rotationIncrement; | 
				
			||||
        if (p_sys->f_rotationAngle <= -ROTATION_MAX) | 
				
			||||
            p_sys->f_rotationIncrement = ROTATION_INCREMENT; | 
				
			||||
        else if (p_sys->f_rotationAngle >= ROTATION_MAX) | 
				
			||||
            p_sys->f_rotationIncrement = -ROTATION_INCREMENT; | 
				
			||||
 | 
				
			||||
        /* Render the frame. */ | 
				
			||||
//        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
				
			||||
//        glPushMatrix();
 | 
				
			||||
//        glRotatef(p_sys->f_rotationAngle, 0, 1, 0);
 | 
				
			||||
//        drawBars(height);
 | 
				
			||||
//        glPopMatrix();
 | 
				
			||||
 | 
				
			||||
        /* Wait to swapp the frame on time. */ | 
				
			||||
//        vlc_tick_wait(block->i_pts + (block->i_length / 2));
 | 
				
			||||
//        vlc_gl_Swap(gl);
 | 
				
			||||
        usleep(block->i_pts + (block->i_length / 2)); | 
				
			||||
 | 
				
			||||
release: | 
				
			||||
        window_close(&wind_ctx); | 
				
			||||
        fft_close(p_state); | 
				
			||||
//        block_Release(block);//TODO
 | 
				
			||||
        if (block->p_buffer) free(block->p_buffer); | 
				
			||||
        free(block); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return NULL; | 
				
			||||
} | 
				
			||||
@ -0,0 +1,77 @@ | 
				
			||||
//
 | 
				
			||||
// Created by frank on 2021/8/16.
 | 
				
			||||
//
 | 
				
			||||
 | 
				
			||||
#ifndef PLAYER_CORE_RUN_FFT_H | 
				
			||||
#define PLAYER_CORE_RUN_FFT_H | 
				
			||||
 | 
				
			||||
#include "vlc_queue.h" | 
				
			||||
#include "fft.h" | 
				
			||||
#include "window.h" | 
				
			||||
 | 
				
			||||
#include <math.h> | 
				
			||||
#include <unistd.h> | 
				
			||||
 | 
				
			||||
/** No error */ | 
				
			||||
#define VLC_SUCCESS        (-0) | 
				
			||||
/** Unspecified error */ | 
				
			||||
#define VLC_EGENERIC       (-1) | 
				
			||||
/** Not enough memory */ | 
				
			||||
#define VLC_ENOMEM         (-2) | 
				
			||||
 | 
				
			||||
typedef int64_t vlc_tick_t; | 
				
			||||
 | 
				
			||||
typedef struct block_t block_t; | 
				
			||||
 | 
				
			||||
struct vlc_block_callbacks | 
				
			||||
{ | 
				
			||||
    void (*free)(block_t *); | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
struct block_t | 
				
			||||
{ | 
				
			||||
    block_t    *p_next; | 
				
			||||
 | 
				
			||||
    uint8_t    *p_buffer; /**< Payload start */ | 
				
			||||
    size_t      i_buffer; /**< Payload length */ | 
				
			||||
    uint8_t    *p_start; /**< Buffer start */ | 
				
			||||
    size_t      i_size; /**< Buffer total size */ | 
				
			||||
 | 
				
			||||
    uint32_t    i_flags; | 
				
			||||
    unsigned    i_nb_samples; /* Used for audio */ | 
				
			||||
 | 
				
			||||
    vlc_tick_t  i_pts; | 
				
			||||
    vlc_tick_t  i_dts; | 
				
			||||
    vlc_tick_t  i_length; | 
				
			||||
 | 
				
			||||
    const struct vlc_block_callbacks *cbs; | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
typedef struct | 
				
			||||
{ | 
				
			||||
//    vlc_thread_t thread;
 | 
				
			||||
    pthread_t thread; | 
				
			||||
 | 
				
			||||
    /* Audio data */ | 
				
			||||
    vlc_queue_t queue; | 
				
			||||
    bool dead; | 
				
			||||
    unsigned i_channels; | 
				
			||||
    unsigned i_prev_nb_samples; | 
				
			||||
    int16_t *p_prev_s16_buff; | 
				
			||||
 | 
				
			||||
    float f_rotationAngle; | 
				
			||||
    float f_rotationIncrement; | 
				
			||||
 | 
				
			||||
    /* FFT window parameters */ | 
				
			||||
    window_param wind_param; | 
				
			||||
} filter_sys_t; | 
				
			||||
 | 
				
			||||
static void *Thread(void *); | 
				
			||||
 | 
				
			||||
/*static*/ int Open(filter_sys_t *p_sys); | 
				
			||||
 | 
				
			||||
/*static*/ block_t *filter_audio(filter_sys_t *p_sys, block_t *p_in_buf); | 
				
			||||
 | 
				
			||||
/*static*/ void Close(filter_sys_t *p_filter); | 
				
			||||
 | 
				
			||||
#endif //PLAYER_CORE_RUN_FFT_H
 | 
				
			||||
@ -0,0 +1,206 @@ | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * fft.c: Iterative implementation of a FFT | 
				
			||||
 ***************************************************************************** | 
				
			||||
 * | 
				
			||||
 * Mainly taken from XMMS's code | 
				
			||||
 * | 
				
			||||
 * Authors: Richard Boulton <richard@tartarus.org> | 
				
			||||
 *          Ralph Loader <suckfish@ihug.co.nz> | 
				
			||||
 * | 
				
			||||
 * 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, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
#include <stdlib.h> | 
				
			||||
#include "fft.h" | 
				
			||||
 | 
				
			||||
#include <math.h> | 
				
			||||
#ifndef PI | 
				
			||||
 #ifdef M_PI | 
				
			||||
  #define PI M_PI | 
				
			||||
 #else | 
				
			||||
  #define PI            3.14159265358979323846  /* pi */ | 
				
			||||
 #endif | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
/******************************************************************************
 | 
				
			||||
 * Local prototypes | 
				
			||||
 *****************************************************************************/ | 
				
			||||
static void fft_prepare(const sound_sample *input, float * re, float * im, | 
				
			||||
                        const unsigned int *bitReverse); | 
				
			||||
static void fft_calculate(float * re, float * im, | 
				
			||||
                          const float *costable, const float *sintable ); | 
				
			||||
static void fft_output(const float *re, const float *im, float *output); | 
				
			||||
static int reverseBits(unsigned int initial); | 
				
			||||
 | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * These functions are the ones called externally | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Initialisation routine - sets up tables and space to work in. | 
				
			||||
 * Returns a pointer to internal state, to be used when performing calls. | 
				
			||||
 * On error, returns NULL. | 
				
			||||
 * The pointer should be freed when it is finished with, by fft_close(). | 
				
			||||
 */ | 
				
			||||
fft_state *visual_fft_init(void) | 
				
			||||
{ | 
				
			||||
    fft_state *p_state; | 
				
			||||
    unsigned int i; | 
				
			||||
 | 
				
			||||
    p_state = malloc( sizeof(*p_state) ); | 
				
			||||
    if(! p_state ) | 
				
			||||
        return NULL; | 
				
			||||
 | 
				
			||||
    for(i = 0; i < FFT_BUFFER_SIZE; i++) | 
				
			||||
    { | 
				
			||||
        p_state->bitReverse[i] = reverseBits(i); | 
				
			||||
    } | 
				
			||||
    for(i = 0; i < FFT_BUFFER_SIZE / 2; i++) | 
				
			||||
    { | 
				
			||||
        float j = 2 * PI * i / FFT_BUFFER_SIZE; | 
				
			||||
        p_state->costable[i] = cos(j); | 
				
			||||
        p_state->sintable[i] = sin(j); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return p_state; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Do all the steps of the FFT, taking as input sound data (as described in | 
				
			||||
 * sound.h) and returning the intensities of each frequency as floats in the | 
				
			||||
 * range 0 to ((FFT_BUFFER_SIZE / 2) * 32768) ^ 2 | 
				
			||||
 * | 
				
			||||
 * The input array is assumed to have FFT_BUFFER_SIZE elements, | 
				
			||||
 * and the output array is assumed to have (FFT_BUFFER_SIZE / 2 + 1) elements. | 
				
			||||
 * state is a (non-NULL) pointer returned by visual_fft_init. | 
				
			||||
 */ | 
				
			||||
void fft_perform(const sound_sample *input, float *output, fft_state *state) { | 
				
			||||
    /* Convert data from sound format to be ready for FFT */ | 
				
			||||
    fft_prepare(input, state->real, state->imag, state->bitReverse ); | 
				
			||||
 | 
				
			||||
    /* Do the actual FFT */ | 
				
			||||
    fft_calculate(state->real, state->imag, state->costable, state->sintable); | 
				
			||||
 | 
				
			||||
    /* Convert the FFT output into intensities */ | 
				
			||||
    fft_output(state->real, state->imag, output); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Free the state. | 
				
			||||
 */ | 
				
			||||
void fft_close(fft_state *state) { | 
				
			||||
    free( state ); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * These functions are called from the other ones | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Prepare data to perform an FFT on | 
				
			||||
 */ | 
				
			||||
static void fft_prepare( const sound_sample *input, float * re, float * im, | 
				
			||||
                         const unsigned int *bitReverse ) { | 
				
			||||
    unsigned int i; | 
				
			||||
    float *p_real = re; | 
				
			||||
    float *p_imag = im; | 
				
			||||
 | 
				
			||||
    /* Get input, in reverse bit order */ | 
				
			||||
    for(i = 0; i < FFT_BUFFER_SIZE; i++) | 
				
			||||
    { | 
				
			||||
        *p_real++ = input[bitReverse[i]]; | 
				
			||||
        *p_imag++ = 0; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Take result of an FFT and calculate the intensities of each frequency | 
				
			||||
 * Note: only produces half as many data points as the input had. | 
				
			||||
 */ | 
				
			||||
static void fft_output(const float * re, const float * im, float *output) | 
				
			||||
{ | 
				
			||||
    float *p_output = output; | 
				
			||||
    const float *p_real   = re; | 
				
			||||
    const float *p_imag   = im; | 
				
			||||
    float *p_end    = output + FFT_BUFFER_SIZE / 2; | 
				
			||||
 | 
				
			||||
    while(p_output <= p_end) | 
				
			||||
    { | 
				
			||||
        *p_output = (*p_real * *p_real) + (*p_imag * *p_imag); | 
				
			||||
        p_output++; p_real++; p_imag++; | 
				
			||||
    } | 
				
			||||
    /* Do divisions to keep the constant and highest frequency terms in scale
 | 
				
			||||
     * with the other terms. */ | 
				
			||||
    *output /= 4; | 
				
			||||
    *p_end /= 4; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Actually perform the FFT | 
				
			||||
 */ | 
				
			||||
static void fft_calculate(float * re, float * im, const float *costable, const float *sintable ) | 
				
			||||
{ | 
				
			||||
    unsigned int i, j, k; | 
				
			||||
    unsigned int exchanges; | 
				
			||||
    float fact_real, fact_imag; | 
				
			||||
    float tmp_real, tmp_imag; | 
				
			||||
    unsigned int factfact; | 
				
			||||
 | 
				
			||||
    /* Set up some variables to reduce calculation in the loops */ | 
				
			||||
    exchanges = 1; | 
				
			||||
    factfact = FFT_BUFFER_SIZE / 2; | 
				
			||||
 | 
				
			||||
    /* Loop through the divide and conquer steps */ | 
				
			||||
    for(i = FFT_BUFFER_SIZE_LOG; i != 0; i--) { | 
				
			||||
        /* In this step, we have 2 ^ (i - 1) exchange groups, each with
 | 
				
			||||
         * 2 ^ (FFT_BUFFER_SIZE_LOG - i) exchanges | 
				
			||||
         */ | 
				
			||||
        /* Loop through the exchanges in a group */ | 
				
			||||
        for(j = 0; j != exchanges; j++) { | 
				
			||||
            /* Work out factor for this exchange
 | 
				
			||||
             * factor ^ (exchanges) = -1 | 
				
			||||
             * So, real = cos(j * PI / exchanges), | 
				
			||||
             *     imag = sin(j * PI / exchanges) | 
				
			||||
             */ | 
				
			||||
            fact_real = costable[j * factfact]; | 
				
			||||
            fact_imag = sintable[j * factfact]; | 
				
			||||
 | 
				
			||||
            /* Loop through all the exchange groups */ | 
				
			||||
            for(k = j; k < FFT_BUFFER_SIZE; k += exchanges << 1) { | 
				
			||||
                int k1 = k + exchanges; | 
				
			||||
                tmp_real = fact_real * re[k1] - fact_imag * im[k1]; | 
				
			||||
                tmp_imag = fact_real * im[k1] + fact_imag * re[k1]; | 
				
			||||
                re[k1] = re[k] - tmp_real; | 
				
			||||
                im[k1] = im[k] - tmp_imag; | 
				
			||||
                re[k]  += tmp_real; | 
				
			||||
                im[k]  += tmp_imag; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        exchanges <<= 1; | 
				
			||||
        factfact >>= 1; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static int reverseBits(unsigned int initial) | 
				
			||||
{ | 
				
			||||
    unsigned int reversed = 0, loop; | 
				
			||||
    for(loop = 0; loop < FFT_BUFFER_SIZE_LOG; loop++) { | 
				
			||||
        reversed <<= 1; | 
				
			||||
        reversed += (initial & 1); | 
				
			||||
        initial >>= 1; | 
				
			||||
    } | 
				
			||||
    return reversed; | 
				
			||||
} | 
				
			||||
@ -0,0 +1,55 @@ | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * fft.h: Headers for iterative implementation of a FFT | 
				
			||||
 ***************************************************************************** | 
				
			||||
 * | 
				
			||||
 * Mainly taken from XMMS's code | 
				
			||||
 * | 
				
			||||
 * Authors: Richard Boulton <richard@tartarus.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, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
#ifndef VLC_VISUAL_FFT_H_ | 
				
			||||
#define VLC_VISUAL_FFT_H_ | 
				
			||||
 | 
				
			||||
#define FFT_BUFFER_SIZE_LOG 9 | 
				
			||||
 | 
				
			||||
#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG) | 
				
			||||
 | 
				
			||||
/* sound sample - should be an signed 16 bit value */ | 
				
			||||
typedef short int sound_sample; | 
				
			||||
 | 
				
			||||
struct _struct_fft_state { | 
				
			||||
     /* Temporary data stores to perform FFT in. */ | 
				
			||||
     float real[FFT_BUFFER_SIZE]; | 
				
			||||
     float imag[FFT_BUFFER_SIZE]; | 
				
			||||
 | 
				
			||||
     /* */ | 
				
			||||
     unsigned int bitReverse[FFT_BUFFER_SIZE]; | 
				
			||||
 | 
				
			||||
     /* The next two tables could be made to use less space in memory, since they
 | 
				
			||||
      * overlap hugely, but hey. */ | 
				
			||||
     float sintable[FFT_BUFFER_SIZE / 2]; | 
				
			||||
     float costable[FFT_BUFFER_SIZE / 2]; | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/* FFT prototypes */ | 
				
			||||
typedef struct _struct_fft_state fft_state; | 
				
			||||
fft_state *visual_fft_init (void); | 
				
			||||
void fft_perform (const sound_sample *input, float *output, fft_state *state); | 
				
			||||
void fft_close (fft_state *state); | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#endif /* include-guard */ | 
				
			||||
@ -0,0 +1,155 @@ | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * queue.c: generic queue (FIFO) | 
				
			||||
 ***************************************************************************** | 
				
			||||
 * Copyright (C) 2020 Rémi Denis-Courmont | 
				
			||||
 * | 
				
			||||
 * This program is free software; you can redistribute it and/or modify it | 
				
			||||
 * under the terms of the GNU Lesser General Public License as published by | 
				
			||||
 * the Free Software Foundation; either version 2.1 of the License, or | 
				
			||||
 * (at your option) any later version. | 
				
			||||
 * | 
				
			||||
 * 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 Lesser General Public License for more details. | 
				
			||||
 * | 
				
			||||
 * You should have received a copy of the GNU Lesser General Public License | 
				
			||||
 * along with this program; if not, write to the Free Software Foundation, | 
				
			||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
#include <assert.h> | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <stdlib.h> | 
				
			||||
 | 
				
			||||
#include "vlc_queue.h" | 
				
			||||
 | 
				
			||||
/* Opaque struct type.
 | 
				
			||||
 * | 
				
			||||
 * ISO C uses the same representation for all pointer-to-struct types. | 
				
			||||
 * Still different pointer types are not compatible, i.e. cannot alias. | 
				
			||||
 * So use memcpy() to read/write pointer values. | 
				
			||||
 */ | 
				
			||||
struct vlc_queue_entry; | 
				
			||||
 | 
				
			||||
static void entry_set(struct vlc_queue_entry **pp, struct vlc_queue_entry *e) | 
				
			||||
{ | 
				
			||||
    memcpy(pp, &e, sizeof (e)); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static struct vlc_queue_entry *entry_get(struct vlc_queue_entry *const *pp) | 
				
			||||
{ | 
				
			||||
    struct vlc_queue_entry *e; | 
				
			||||
 | 
				
			||||
    memcpy(&e, pp, sizeof (e)); | 
				
			||||
    return e; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static struct vlc_queue_entry **next_p(const struct vlc_queue_entry *e, | 
				
			||||
                                       ptrdiff_t offset) | 
				
			||||
{ | 
				
			||||
    return (struct vlc_queue_entry **)(((unsigned char *)e) + offset); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static void next_set(struct vlc_queue_entry *e, struct vlc_queue_entry *next, | 
				
			||||
                     ptrdiff_t offset) | 
				
			||||
{ | 
				
			||||
    entry_set(next_p(e, offset), next); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
static struct vlc_queue_entry *next_get(const struct vlc_queue_entry *e, | 
				
			||||
                                        ptrdiff_t offset) | 
				
			||||
{ | 
				
			||||
    return entry_get(next_p(e, offset)); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
void vlc_queue_Init(vlc_queue_t *q, ptrdiff_t next_offset) | 
				
			||||
{ | 
				
			||||
    q->first = NULL; | 
				
			||||
    q->lastp = &q->first; | 
				
			||||
    q->next_offset = next_offset; | 
				
			||||
    pthread_mutex_init(&q->lock, NULL); | 
				
			||||
    pthread_cond_init(&q->wait, NULL); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
void vlc_queue_EnqueueUnlocked(vlc_queue_t *q, void *entry) | 
				
			||||
{ | 
				
			||||
    struct vlc_queue_entry **lastp; | 
				
			||||
    const ptrdiff_t offset = q->next_offset; | 
				
			||||
 | 
				
			||||
//    vlc_mutex_assert(&q->lock);
 | 
				
			||||
    assert(entry_get(q->lastp) == NULL); | 
				
			||||
    entry_set(q->lastp, entry); | 
				
			||||
 | 
				
			||||
    for (lastp = q->lastp; entry != NULL; entry = next_get(entry, offset)) | 
				
			||||
        lastp = next_p(entry, offset); | 
				
			||||
 | 
				
			||||
    q->lastp = lastp; | 
				
			||||
    vlc_queue_Signal(q); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
void *vlc_queue_DequeueUnlocked(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
//    vlc_mutex_assert(&q->lock);
 | 
				
			||||
 | 
				
			||||
    void *entry = q->first; | 
				
			||||
    const ptrdiff_t offset = q->next_offset; | 
				
			||||
 | 
				
			||||
    if (entry != NULL) { | 
				
			||||
        struct vlc_queue_entry *next = next_get(entry, offset); | 
				
			||||
 | 
				
			||||
        next_set(entry, NULL, offset); | 
				
			||||
        q->first = next; | 
				
			||||
 | 
				
			||||
        if (next == NULL) | 
				
			||||
            q->lastp = &q->first; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return entry; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
void *vlc_queue_DequeueAllUnlocked(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
//    vlc_mutex_assert(&q->lock);
 | 
				
			||||
 | 
				
			||||
    void *entry = q->first; | 
				
			||||
 | 
				
			||||
    q->first = NULL; | 
				
			||||
    q->lastp = &q->first; | 
				
			||||
 | 
				
			||||
    return entry; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
void vlc_queue_Enqueue(vlc_queue_t *q, void *entry) | 
				
			||||
{ | 
				
			||||
    vlc_queue_Lock(q); | 
				
			||||
    vlc_queue_EnqueueUnlocked(q, entry); | 
				
			||||
    vlc_queue_Unlock(q); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
void *vlc_queue_Dequeue(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
    void *entry; | 
				
			||||
 | 
				
			||||
    vlc_queue_Lock(q); | 
				
			||||
//    vlc_testcancel();
 | 
				
			||||
 | 
				
			||||
    while (vlc_queue_IsEmpty(q)) | 
				
			||||
        vlc_queue_Wait(q); | 
				
			||||
 | 
				
			||||
    entry = vlc_queue_DequeueUnlocked(q); | 
				
			||||
    vlc_queue_Unlock(q); | 
				
			||||
 | 
				
			||||
    return entry; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
void *vlc_queue_DequeueAll(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
    void *entry; | 
				
			||||
 | 
				
			||||
    vlc_queue_Lock(q); | 
				
			||||
    entry = vlc_queue_DequeueAllUnlocked(q); | 
				
			||||
    vlc_queue_Unlock(q); | 
				
			||||
 | 
				
			||||
    return entry; | 
				
			||||
} | 
				
			||||
@ -0,0 +1,260 @@ | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * vlc_queue.h: generic queue functions | 
				
			||||
 ***************************************************************************** | 
				
			||||
 * Copyright (C) 2020 Rémi Denis-Courmont | 
				
			||||
 * | 
				
			||||
 * This program is free software; you can redistribute it and/or modify it | 
				
			||||
 * under the terms of the GNU Lesser General Public License as published by | 
				
			||||
 * the Free Software Foundation; either version 2.1 of the License, or | 
				
			||||
 * (at your option) any later version. | 
				
			||||
 * | 
				
			||||
 * 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 Lesser General Public License for more details. | 
				
			||||
 * | 
				
			||||
 * You should have received a copy of the GNU Lesser General Public License | 
				
			||||
 * along with this program; if not, write to the Free Software Foundation, | 
				
			||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
#ifndef VLC_QUEUE_H | 
				
			||||
#define VLC_QUEUE_H | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @defgroup queue Thread-safe queues (FIFO) | 
				
			||||
 * @ingroup cext | 
				
			||||
 * @{ | 
				
			||||
 * @file vlc_queue.h | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include <stdbool.h> | 
				
			||||
#include <stdint.h> | 
				
			||||
#include <string.h> | 
				
			||||
#include <pthread.h> | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Opaque type for queue entry. | 
				
			||||
 */ | 
				
			||||
struct vlc_queue_entry; | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Thread-safe queue (a.k.a. FIFO). | 
				
			||||
 */ | 
				
			||||
typedef struct vlc_queue | 
				
			||||
{ | 
				
			||||
    struct vlc_queue_entry *first; | 
				
			||||
    struct vlc_queue_entry **lastp; | 
				
			||||
    ptrdiff_t next_offset; | 
				
			||||
//    vlc_mutex_t lock;
 | 
				
			||||
    pthread_mutex_t lock; | 
				
			||||
//    vlc_cond_t wait;
 | 
				
			||||
    pthread_cond_t wait; | 
				
			||||
} vlc_queue_t; | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Initializes a queue. | 
				
			||||
 * | 
				
			||||
 * @param queue storage space for the queue | 
				
			||||
 * @param next_offset offset of the pointer to the next element | 
				
			||||
 *                    within a queue entry (as per @c offsetof()) | 
				
			||||
 */ | 
				
			||||
void vlc_queue_Init(vlc_queue_t *queue, ptrdiff_t next_offset); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @defgroup queue_ll Queue internals | 
				
			||||
 * | 
				
			||||
 * Low-level queue functions. | 
				
			||||
 * | 
				
			||||
 * In some cases, the high-level queue functions do not exactly fit the | 
				
			||||
 * use case requirements, and it is necessary to access the queue internals. | 
				
			||||
 * This typically occurs when threads wait for elements to be added to the | 
				
			||||
 * queue at the same time as some other type of events. | 
				
			||||
 * @{ | 
				
			||||
 */ | 
				
			||||
/**
 | 
				
			||||
 * Locks a queue. | 
				
			||||
 * | 
				
			||||
 * No more than one thread can lock a queue at any given time, and no other | 
				
			||||
 * thread can modify the queue while it is locked. | 
				
			||||
 * Accordingly, if the queue is already locked by another thread, this function | 
				
			||||
 * waits. | 
				
			||||
 * | 
				
			||||
 * Use vlc_queue_Unlock() to release the lock. | 
				
			||||
 * | 
				
			||||
 * @warning Recursively locking a single queue is undefined. | 
				
			||||
 * Also locking more than one queue at a time may lead to lock inversion: | 
				
			||||
 * mind the locking order! | 
				
			||||
 */ | 
				
			||||
static inline void vlc_queue_Lock(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
    pthread_mutex_lock(&q->lock); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Unlocks a queue. | 
				
			||||
 * | 
				
			||||
 * This releases the lock on a queue, allowing other threads to manipulate the | 
				
			||||
 * queue. The behaviour is undefined if the calling thread is not holding the | 
				
			||||
 * queue lock. | 
				
			||||
 */ | 
				
			||||
static inline void vlc_queue_Unlock(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
    pthread_mutex_unlock(&q->lock); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Wakes one thread waiting for a queue entry up. | 
				
			||||
 */ | 
				
			||||
static inline void vlc_queue_Signal(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
    pthread_cond_signal(&q->wait); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Waits for a queue entry. | 
				
			||||
 * | 
				
			||||
 * @note This function is a cancellation point. | 
				
			||||
 * In case of cancellation, the queue will be locked, | 
				
			||||
 * as is consistent for condition variable semantics. | 
				
			||||
 * | 
				
			||||
 * @bug This function should probably not be aware of cancellation. | 
				
			||||
 */ | 
				
			||||
static inline void vlc_queue_Wait(vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
    pthread_cond_wait(&q->wait, &q->lock); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Queues an entry (without locking). | 
				
			||||
 * | 
				
			||||
 * This function enqueues an entry, or rather a linked-list of entries, in a | 
				
			||||
 * thread-safe queue, without taking the queue lock. | 
				
			||||
 * | 
				
			||||
 * @warning It is assumed that the caller already holds the queue lock; | 
				
			||||
 * otherwise the behaviour is undefined. | 
				
			||||
 * | 
				
			||||
 * @param entry NULL-terminated list of entries to queue | 
				
			||||
 *              (if NULL, this function has no effects) | 
				
			||||
 */ | 
				
			||||
void vlc_queue_EnqueueUnlocked(vlc_queue_t *, void *entry); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Dequeues the oldest entry (without locking). | 
				
			||||
 * | 
				
			||||
 * This function dequeues an entry from a thread-safe queue. It is assumed | 
				
			||||
 * that the caller already holds the queue lock; otherwise the behaviour is | 
				
			||||
 * undefined. | 
				
			||||
 * | 
				
			||||
 * @warning It is assumed that the caller already holds the queue lock; | 
				
			||||
 * otherwise the behaviour is undefined. | 
				
			||||
 * | 
				
			||||
 * @return the first entry in the queue, or NULL if the queue is empty | 
				
			||||
 */ | 
				
			||||
void *vlc_queue_DequeueUnlocked(vlc_queue_t *); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Dequeues all entries (without locking). | 
				
			||||
 * | 
				
			||||
 * This is equivalent to calling vlc_queue_DequeueUnlocked() repeatedly until | 
				
			||||
 * the queue is emptied. However this function is much faster than that, as it | 
				
			||||
 * does not need to update the linked-list pointers. | 
				
			||||
 * | 
				
			||||
 * @warning It is assumed that the caller already holds the queue lock; | 
				
			||||
 * otherwise the behaviour is undefined. | 
				
			||||
 * | 
				
			||||
 * @return a linked-list of all entries (possibly NULL if none) | 
				
			||||
 */ | 
				
			||||
void *vlc_queue_DequeueAllUnlocked(vlc_queue_t *); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Checks if a queue is empty (without locking). | 
				
			||||
 * | 
				
			||||
 * @warning It is assumed that the caller already holds the queue lock; | 
				
			||||
 * otherwise the behaviour is undefined. | 
				
			||||
 * | 
				
			||||
 * @retval false the queue contains one or more entries | 
				
			||||
 * @retval true the queue is empty | 
				
			||||
 */ | 
				
			||||
static inline bool vlc_queue_IsEmpty(const vlc_queue_t *q) | 
				
			||||
{ | 
				
			||||
    return q->first == NULL; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** @} */ | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Queues an entry. | 
				
			||||
 * | 
				
			||||
 * This function enqueues an entry, or rather a linked-list of entries, in a | 
				
			||||
 * thread-safe queue. | 
				
			||||
 * | 
				
			||||
 * @param entry list of entries (if NULL, this function has no effects) | 
				
			||||
 */ | 
				
			||||
void vlc_queue_Enqueue(vlc_queue_t *, void *entry); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Dequeues the oldest entry. | 
				
			||||
 * | 
				
			||||
 * This function dequeues an entry from a thread-safe queue. If the queue is | 
				
			||||
 * empty, it will wait until at least one entry is available. | 
				
			||||
 * | 
				
			||||
 * @param offset offset of the next pointer within a queue entry | 
				
			||||
 * | 
				
			||||
 * @return the first entry in the queue, or NULL if the queue is empty | 
				
			||||
 */ | 
				
			||||
void *vlc_queue_Dequeue(vlc_queue_t *); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Dequeues all entries. | 
				
			||||
 * | 
				
			||||
 * This is equivalent to calling vlc_queue_Dequeue() repeatedly until the queue | 
				
			||||
 * is emptied. However this function is much faster than that, as it | 
				
			||||
 * does not need to update the linked-list pointers. | 
				
			||||
 * | 
				
			||||
 * @return a linked-list of all entries (possibly NULL if none) | 
				
			||||
 */ | 
				
			||||
void *vlc_queue_DequeueAll(vlc_queue_t *); | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * @defgroup queue_killable Killable queues | 
				
			||||
 * | 
				
			||||
 * Thread-safe queues with an end flag. | 
				
			||||
 * | 
				
			||||
 * @{ | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Marks a queue ended. | 
				
			||||
 */ | 
				
			||||
static inline void vlc_queue_Kill(vlc_queue_t *q, | 
				
			||||
                                  bool */*restrict*/ tombstone) | 
				
			||||
{ | 
				
			||||
    vlc_queue_Lock(q); | 
				
			||||
    *tombstone = true; | 
				
			||||
    vlc_queue_Signal(q); | 
				
			||||
    vlc_queue_Unlock(q); | 
				
			||||
    pthread_cond_destroy(&q->wait); | 
				
			||||
    pthread_mutex_destroy(&q->lock); | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/**
 | 
				
			||||
 * Dequeues one entry from a killable queue. | 
				
			||||
 * | 
				
			||||
 * @return an entry, or NULL if the queue is empty and has been ended. | 
				
			||||
 */ | 
				
			||||
static inline void *vlc_queue_DequeueKillable(vlc_queue_t *q, | 
				
			||||
                                              bool */*restrict*/ tombstone) | 
				
			||||
{ | 
				
			||||
    void *entry; | 
				
			||||
 | 
				
			||||
    vlc_queue_Lock(q); | 
				
			||||
    while (vlc_queue_IsEmpty(q) && !*tombstone) | 
				
			||||
        vlc_queue_Wait(q); | 
				
			||||
 | 
				
			||||
    entry = vlc_queue_DequeueUnlocked(q); | 
				
			||||
    vlc_queue_Unlock(q); | 
				
			||||
    return entry; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
#endif | 
				
			||||
@ -0,0 +1,227 @@ | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * window.c : Implementation of FFT window routines | 
				
			||||
 ***************************************************************************** | 
				
			||||
 * Copyright (C) 2014 Ronald Wright | 
				
			||||
 * | 
				
			||||
 * Author: Ronald Wright <logiconcepts819@gmail.com> | 
				
			||||
 * | 
				
			||||
 * This program is free software; you can redistribute it and/or modify it | 
				
			||||
 * under the terms of the GNU Lesser General Public License as published by | 
				
			||||
 * the Free Software Foundation; either version 2.1 of the License, or | 
				
			||||
 * (at your option) any later version. | 
				
			||||
 * | 
				
			||||
 * 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 Lesser General Public License for more details. | 
				
			||||
 * | 
				
			||||
 * You should have received a copy of the GNU Lesser General Public License | 
				
			||||
 * along with this program; if not, write to the Free Software Foundation, | 
				
			||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
#include <math.h> | 
				
			||||
#include "window.h" | 
				
			||||
 | 
				
			||||
#include <assert.h> | 
				
			||||
 | 
				
			||||
/* Flat top window coefficients */ | 
				
			||||
#define FT_A0 1.000f | 
				
			||||
#define FT_A1 1.930f | 
				
			||||
#define FT_A2 1.290f | 
				
			||||
#define FT_A3 0.388f | 
				
			||||
#define FT_A4 0.028f | 
				
			||||
 | 
				
			||||
/* Blackman-Harris window coefficients */ | 
				
			||||
#define BH_A0 0.35875f | 
				
			||||
#define BH_A1 0.48829f | 
				
			||||
#define BH_A2 0.14128f | 
				
			||||
#define BH_A3 0.01168f | 
				
			||||
 | 
				
			||||
/* Window functions supported by VLC. These are the typical window types used
 | 
				
			||||
 * in spectrum analyzers. */ | 
				
			||||
#define NB_WINDOWS 5 | 
				
			||||
static const char * const window_list[NB_WINDOWS] = { | 
				
			||||
        "none", "hann", "flattop", "blackmanharris", "kaiser", | 
				
			||||
}; | 
				
			||||
static const char * const window_list_text[NB_WINDOWS] = { | 
				
			||||
//        N_("None"), N_("Hann"), N_("Flat Top"), N_("Blackman-Harris"), N_("Kaiser"),
 | 
				
			||||
        "None", "Hann", "Flat Top", "Blackman-Harris", "Kaiser", | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * The modified Bessel function I0(x).  See Chapter 6 of the "Numerical Recipes | 
				
			||||
 * in C: The Art of Scientific Computing" book at | 
				
			||||
 * http://www.aip.de/groups/soe/local/numres/bookcpdf/c6-6.pdf
 | 
				
			||||
 */ | 
				
			||||
static float bessi0(float x) | 
				
			||||
{ | 
				
			||||
    float ax, ans; | 
				
			||||
    double y; /* Accumulate polynomials in double precision. */ | 
				
			||||
    if( ( ax = fabsf( x ) ) < 3.75f ) /* Polynomial fit. */ | 
				
			||||
    { | 
				
			||||
        y = x / 3.75; | 
				
			||||
        y *= y; | 
				
			||||
        ans = 1.0 + y * ( 3.5156229 + y * ( 3.0899424 + y * ( 1.2067492 | 
				
			||||
                  + y * ( 0.2659732 + y * ( 0.360768e-1 | 
				
			||||
                  + y * 0.45813e-2 ) ) ) ) ); | 
				
			||||
    } | 
				
			||||
    else | 
				
			||||
    { | 
				
			||||
        y = 3.75 / ax; | 
				
			||||
        ans = ( exp( ax ) / sqrt( ax ) ) * ( 0.39894228 + y * ( 0.1328592e-1 | 
				
			||||
            + y * ( 0.225319e-2 + y * ( -0.157565e-2 + y * ( 0.916281e-2 | 
				
			||||
            + y * ( -0.2057706e-1 + y * ( 0.2635537e-1 + y * ( -0.1647633e-1 | 
				
			||||
            + y * 0.392377e-2 ) ) ) ) ) ) ) ); | 
				
			||||
    } | 
				
			||||
    return ans; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Obtain the window type from the window type variable. | 
				
			||||
 */ | 
				
			||||
void window_get_param(void * p_aout, window_param * p_param) | 
				
			||||
{ | 
				
			||||
    /* Fetch Kaiser parameter */ | 
				
			||||
    p_param->f_kaiser_alpha = 1; //TODO var_InheritFloat( p_aout, "effect-kaiser-param" );
 | 
				
			||||
 | 
				
			||||
    /* Fetch window type */ | 
				
			||||
    char * psz_preset = "hann"; //TODO var_InheritString( p_aout, "effect-fft-window" );
 | 
				
			||||
    if( !psz_preset ) | 
				
			||||
    { | 
				
			||||
        goto no_preset; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    for( int i = 0; i < NB_WINDOWS; i++ ) | 
				
			||||
    { | 
				
			||||
        if( !strcasecmp( psz_preset, window_list[i] ) ) | 
				
			||||
        { | 
				
			||||
//            free( psz_preset );//TODO
 | 
				
			||||
            p_param->wind_type = i; | 
				
			||||
            return; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
//    free( psz_preset );//TODO
 | 
				
			||||
 | 
				
			||||
no_preset: | 
				
			||||
//    msg_Warn( p_aout, "No matching window preset found; using rectangular "
 | 
				
			||||
//                      "window (i.e. no window)" );
 | 
				
			||||
    p_param->wind_type = NONE; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Initialization routine - sets up a lookup table for scaling a sample of data | 
				
			||||
 * by window data.  If the lookup table is successfully allocated, its memory | 
				
			||||
 * location and its specified size are stored at the specified memory location | 
				
			||||
 * of the internal context. | 
				
			||||
 * Returns true if initialization succeeded and returns false otherwise. | 
				
			||||
 * The internal context should be freed when it is finished with, by | 
				
			||||
 * window_close(). | 
				
			||||
 */ | 
				
			||||
bool window_init(int i_buffer_size, window_param * p_param, window_context * p_ctx) | 
				
			||||
{ | 
				
			||||
    float * pf_table = NULL; | 
				
			||||
    window_type wind_type = p_param->wind_type; | 
				
			||||
 | 
				
			||||
    if( wind_type != HANN && wind_type != FLATTOP | 
				
			||||
                          && wind_type != BLACKMANHARRIS | 
				
			||||
                          && wind_type != KAISER ) | 
				
			||||
    { | 
				
			||||
        /* Assume a rectangular window (i.e. no window) */ | 
				
			||||
        i_buffer_size = 0; | 
				
			||||
        goto exit; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
//    pf_table = vlc_alloc( i_buffer_size, sizeof( *pf_table ) );
 | 
				
			||||
    pf_table = (float * )malloc( i_buffer_size * sizeof(*pf_table)); | 
				
			||||
    if( !pf_table ) | 
				
			||||
    { | 
				
			||||
        /* Memory allocation failed */ | 
				
			||||
        return false; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    int i_buffer_size_minus_1 = i_buffer_size - 1; | 
				
			||||
    switch( wind_type ) | 
				
			||||
    { | 
				
			||||
    case HANN: | 
				
			||||
        /* Hann window */ | 
				
			||||
        for( int i = 0; i < i_buffer_size; i++ ) | 
				
			||||
        { | 
				
			||||
            float f_val = (float) i / (float) i_buffer_size_minus_1; | 
				
			||||
            pf_table[i] = 0.5f - 0.5f * cosf( 2.0f * (float) M_PI * f_val ); | 
				
			||||
        } | 
				
			||||
        break; | 
				
			||||
    case FLATTOP: | 
				
			||||
        /* Flat top window */ | 
				
			||||
        for( int i = 0; i < i_buffer_size; i++ ) | 
				
			||||
        { | 
				
			||||
            float f_val = (float) i / (float) i_buffer_size_minus_1; | 
				
			||||
            pf_table[i] = FT_A0 | 
				
			||||
                        - FT_A1 * cosf( 2.0f * (float) M_PI * f_val ) | 
				
			||||
                        + FT_A2 * cosf( 4.0f * (float) M_PI * f_val ) | 
				
			||||
                        - FT_A3 * cosf( 6.0f * (float) M_PI * f_val ) | 
				
			||||
                        + FT_A4 * cosf( 8.0f * (float) M_PI * f_val ); | 
				
			||||
        } | 
				
			||||
        break; | 
				
			||||
    case BLACKMANHARRIS: | 
				
			||||
        /* Blackman-Harris window */ | 
				
			||||
        for( int i = 0; i < i_buffer_size; i++ ) | 
				
			||||
        { | 
				
			||||
            float f_val = (float) i / (float) i_buffer_size_minus_1; | 
				
			||||
            pf_table[i] = BH_A0 | 
				
			||||
                        - BH_A1 * cosf( 2.0f * (float) M_PI * f_val ) | 
				
			||||
                        + BH_A2 * cosf( 4.0f * (float) M_PI * f_val ) | 
				
			||||
                        - BH_A3 * cosf( 6.0f * (float) M_PI * f_val ); | 
				
			||||
        } | 
				
			||||
        break; | 
				
			||||
    case KAISER: | 
				
			||||
    { | 
				
			||||
        /* Kaiser window */ | 
				
			||||
        float f_pialph = (float) M_PI * p_param->f_kaiser_alpha; | 
				
			||||
        float f_bessi0_pialph = bessi0( f_pialph ); | 
				
			||||
        for( int i = 0; i < i_buffer_size; i++ ) | 
				
			||||
        { | 
				
			||||
            float f_val = (float) i / (float) i_buffer_size_minus_1; | 
				
			||||
            float f_term_to_square = 2.0f * f_val - 1.0f; | 
				
			||||
            float f_sqd_term = f_term_to_square * f_term_to_square; | 
				
			||||
            float f_sqr_term = sqrtf( 1.0f - f_sqd_term ); | 
				
			||||
            pf_table[i] = bessi0( f_pialph * f_sqr_term ) / f_bessi0_pialph; | 
				
			||||
        } | 
				
			||||
        break; | 
				
			||||
    } | 
				
			||||
    default: | 
				
			||||
        /* We should not reach here */ | 
				
			||||
//        vlc_assert_unreachable();
 | 
				
			||||
        break; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
exit: | 
				
			||||
    p_ctx->pf_window_table = pf_table; | 
				
			||||
    p_ctx->i_buffer_size = i_buffer_size; | 
				
			||||
    return true; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Perform an in-place scaling of the input buffer by the window data | 
				
			||||
 * referenced from the specified context. | 
				
			||||
 */ | 
				
			||||
void window_scale_in_place(int16_t * p_buffer, window_context * p_ctx) | 
				
			||||
{ | 
				
			||||
    for(int i = 0; i < p_ctx->i_buffer_size; i++) | 
				
			||||
    { | 
				
			||||
        p_buffer[i] *= p_ctx->pf_window_table[i]; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/*
 | 
				
			||||
 * Free the context. | 
				
			||||
 */ | 
				
			||||
void window_close(window_context * p_ctx) | 
				
			||||
{ | 
				
			||||
    if(p_ctx->pf_window_table) | 
				
			||||
    { | 
				
			||||
        free(p_ctx->pf_window_table); | 
				
			||||
        p_ctx->pf_window_table = NULL; | 
				
			||||
        p_ctx->i_buffer_size = 0; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,69 @@ | 
				
			||||
/*****************************************************************************
 | 
				
			||||
 * window.h : Header for FFT window routines | 
				
			||||
 ***************************************************************************** | 
				
			||||
 * Copyright (C) 2014 Ronald Wright | 
				
			||||
 * | 
				
			||||
 * Author: Ronald Wright <logiconcepts819@gmail.com> | 
				
			||||
 * | 
				
			||||
 * This program is free software; you can redistribute it and/or modify it | 
				
			||||
 * under the terms of the GNU Lesser General Public License as published by | 
				
			||||
 * the Free Software Foundation; either version 2.1 of the License, or | 
				
			||||
 * (at your option) any later version. | 
				
			||||
 * | 
				
			||||
 * 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 Lesser General Public License for more details. | 
				
			||||
 * | 
				
			||||
 * You should have received a copy of the GNU Lesser General Public License | 
				
			||||
 * along with this program; if not, write to the Free Software Foundation, | 
				
			||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. | 
				
			||||
 *****************************************************************************/ | 
				
			||||
 | 
				
			||||
#ifndef VLC_VISUAL_WINDOW_H_ | 
				
			||||
#define VLC_VISUAL_WINDOW_H_ | 
				
			||||
 | 
				
			||||
#include <stdlib.h> | 
				
			||||
#include <string.h> | 
				
			||||
 | 
				
			||||
#ifndef __cplusplus | 
				
			||||
# include <stdbool.h> | 
				
			||||
#endif | 
				
			||||
 | 
				
			||||
/* Window type enum */ | 
				
			||||
enum _enum_window_type { NONE, HANN, FLATTOP, BLACKMANHARRIS, KAISER }; | 
				
			||||
 | 
				
			||||
/* Window context structure */ | 
				
			||||
struct _struct_window_context { | 
				
			||||
 | 
				
			||||
    /* Storage for window function values */ | 
				
			||||
    float * pf_window_table; | 
				
			||||
 | 
				
			||||
    /* Buffer size for the window */ | 
				
			||||
    int i_buffer_size; | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
typedef enum _enum_window_type window_type; | 
				
			||||
 | 
				
			||||
/* Window parameter structure */ | 
				
			||||
struct _struct_window_param { | 
				
			||||
 | 
				
			||||
    /* Window type */ | 
				
			||||
    window_type wind_type; | 
				
			||||
 | 
				
			||||
    /* Kaiser window parameter */ | 
				
			||||
    float f_kaiser_alpha; | 
				
			||||
}; | 
				
			||||
 | 
				
			||||
/* Prototypes for the window function */ | 
				
			||||
typedef struct _struct_window_context window_context; | 
				
			||||
typedef struct _struct_window_param window_param; | 
				
			||||
void window_get_param(void * p_aout, window_param * p_param); | 
				
			||||
bool window_init(int i_buffer_size, window_param * p_param, window_context * p_ctx); | 
				
			||||
void window_scale_in_place(int16_t * p_buffer, window_context * p_ctx); | 
				
			||||
void window_close(window_context * p_ctx); | 
				
			||||
 | 
				
			||||
/* Macro for defining a new window context */ | 
				
			||||
#define DEFINE_WIND_CONTEXT(name) window_context name = {NULL, 0} | 
				
			||||
 | 
				
			||||
#endif /* include-guard */ | 
				
			||||
					Loading…
					
					
				
		Reference in new issue