change to class

dev
xufulong 3 years ago
parent c3bf79d5ac
commit 3fab7f9efe
  1. 2
      app/CMakeLists.txt
  2. 18
      app/src/main/cpp/audio_player.cpp
  3. 372
      app/src/main/cpp/visualizer/execute_fft.cpp
  4. 66
      app/src/main/cpp/visualizer/execute_fft.h
  5. 220
      app/src/main/cpp/visualizer/frank_visualizer.cpp
  6. 54
      app/src/main/cpp/visualizer/frank_visualizer.h

@ -37,7 +37,7 @@ add_library( # Sets the name of the library.
src/main/cpp/visualizer/fft.cpp
src/main/cpp/visualizer/fixed_fft.cpp
src/main/cpp/visualizer/block_queue.c
src/main/cpp/visualizer/execute_fft.cpp
src/main/cpp/visualizer/frank_visualizer.cpp
src/main/cpp/visualizer/window.cpp
)

@ -4,6 +4,7 @@
#include <jni.h>
#include <cstdlib>
#include <unistd.h>
#include "visualizer/frank_visualizer.h"
#ifdef __cplusplus
extern "C" {
@ -19,8 +20,6 @@ extern "C" {
#include "libavutil/opt.h"
#include "ffmpeg_jni_define.h"
#include "visualizer/execute_fft.h"
#ifdef __cplusplus
}
#endif
@ -33,6 +32,7 @@ extern "C" {
int filter_again = 0;
int filter_release = 0;
const char *filter_desc = "superequalizer=6b=4:8b=5:10b=5";
FrankVisualizer *mVisualizer;
void fft_callback(JNIEnv *jniEnv, jobject thiz, jmethodID fft_method, int8_t* arg, int samples);
@ -285,8 +285,8 @@ AUDIO_PLAYER_FUNC(void, play, jstring input_jstr, jstring filter_jstr) {
jmethodID fft_method = env->GetMethodID(player_class, "fftCallbackFromJNI", "([B)V");
auto *fft_filter = static_cast<filter_sys_t *>(malloc(sizeof(filter_sys_t)));
init_visualizer(fft_filter);
mVisualizer = new FrankVisualizer();
mVisualizer->init_visualizer();
//read audio frame
while (av_read_frame(pFormatCtx, packet) >= 0 && !filter_release) {
@ -311,10 +311,10 @@ AUDIO_PLAYER_FUNC(void, play, jstring input_jstr, jstring filter_jstr) {
int nb_samples = frame->nb_samples < MAX_FFT_SIZE ? frame->nb_samples : MAX_FFT_SIZE;
if (nb_samples >= MIN_FFT_SIZE) {
fft_filter->nb_samples = nb_samples;
memcpy(fft_filter->data, frame->data[0], nb_samples);
fft_once(fft_filter);
fft_callback(env, thiz, fft_method, fft_filter->output, fft_filter->out_samples);
mVisualizer->fft_context->nb_samples = nb_samples;
memcpy(mVisualizer->fft_context->data, frame->data[0], nb_samples);
mVisualizer->fft_run();
fft_callback(env, thiz, fft_method, mVisualizer->fft_context->output, mVisualizer->fft_context->out_samples);
}
ret = av_buffersrc_add_frame(audioSrcContext, frame);
@ -364,7 +364,7 @@ end:
env->CallVoidMethod(thiz, releaseMethod);
filter_again = 0;
filter_release = 0;
release_visualizer(fft_filter);
mVisualizer->release_visualizer();
LOGE(TAG, "audio release...");
}

@ -1,372 +0,0 @@
//
// 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 NB_BANDS 20
#define BAR_DECREMENT .075f
int open_visualizer(filter_sys_t *p_sys)
{
if (p_sys == nullptr)
return -1;
p_sys->i_channels = 1;
p_sys->i_prev_nb_samples = 0;
p_sys->p_prev_s16_buff = nullptr;
p_sys->wind_param = new window_param();
/* Fetch the FFT window parameters */
window_get_param(p_sys->wind_param);
/* Create the FIFO for the audio data. */
vlc_queue_t *queue = vlc_queue_init(5);
p_sys->queue = *queue;
p_sys->dead = false;
pthread_create (&p_sys->thread, nullptr, fft_thread, p_sys);
return 0;
}
block_t *filter_audio(filter_sys_t *p_sys, void *p_in_buf)
{
return (block_t *) vlc_queue_push(&p_sys->queue, p_in_buf);
}
void close_visualizer(filter_sys_t *p_filter)
{
filter_sys_t *p_sys = p_filter;
vlc_queue_free(&p_sys->queue);
pthread_join(p_sys->thread, nullptr);
if (p_sys->p_prev_s16_buff) {
delete [] (p_sys->p_prev_s16_buff);
}
if (p_sys->wind_param) {
delete (p_sys->wind_param);
}
if (p_sys->data) {
delete [] (p_sys->data);
}
if (p_sys->output) {
delete [] (p_sys->output);
}
delete (p_sys);
}
static void *fft_thread(void *p_data)
{
auto *p_sys = (filter_sys_t*)p_data;
block_t *block;
float height[NB_BANDS] = {0};
LOGE("start FFT thread...");
while ((block = (block_t *) vlc_queue_pop(&p_sys->queue)))
{
LOGE("running FFT transform...");
/* 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 = nullptr; /* 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 */
auto *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)
{
if (p_sys->p_prev_s16_buff) delete [] (p_sys->p_prev_s16_buff);
p_sys->p_prev_s16_buff = new int16_t [block->i_nb_samples * p_sys->i_channels];
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];
}
usleep(10*1000 /*block->i_pts + (block->i_length / 2)*/);
block->fft_callback.callback(p_dest);
release:
window_close(&wind_ctx);
fft_close(p_state);
}
return nullptr;
}
int init_visualizer(filter_sys_t *p_filter)
{
if (p_filter == nullptr)
return -1;
p_filter->i_channels = 1;
p_filter->i_prev_nb_samples = 0;
p_filter->p_prev_s16_buff = nullptr;
p_filter->wind_param = new window_param();
/* Fetch the FFT window parameters */
window_get_param(p_filter->wind_param);
p_filter->data = nullptr;
p_filter->data_size = 0;
p_filter->nb_samples = 0;
#ifdef FIXED_FFT
p_filter->out_samples = 512;
#else
p_filter->out_samples = FFT_BUFFER_SIZE;
#endif
p_filter->output = new int8_t[p_filter->out_samples];
if (!p_filter->output) return -1;
p_filter->data_size = MAX_FFT_SIZE;
p_filter->data = new uint8_t[MAX_FFT_SIZE];
if (!p_filter->data) {
return -1;
}
return 0;
}
void release_visualizer(filter_sys_t *p_filter)
{
if (!p_filter) return;
if (p_filter->p_prev_s16_buff) {
delete [] (p_filter->p_prev_s16_buff);
}
if (p_filter->wind_param) {
delete (p_filter->wind_param);
}
if (p_filter->data) {
delete [] (p_filter->data);
}
if (p_filter->output) {
delete [] (p_filter->output);
}
delete (p_filter);
}
void fft_float(filter_sys_t *p_sys)
{
int nb_samples = p_sys->nb_samples;
int out_samples = p_sys->out_samples;
fft_state *p_state = nullptr; /* internal FFT data */
DEFINE_WIND_CONTEXT(wind_ctx); /* internal window data */
unsigned i;
float p_output[out_samples]; /* Raw FFT Result */
int16_t p_buffer1[out_samples]; /* Buffer on which we perform */
auto *p_buffl = (float*)p_sys->data; /* Original buffer */
int16_t *p_buffs; /* int16_t converted buffer */
int16_t *p_s16_buff; /* int16_t converted buffer */
if (!nb_samples) {
LOGE("no samples yet...");
goto release;
}
/* Allocate the buffer only if the number of samples change */
if (nb_samples != p_sys->i_prev_nb_samples) {
if (p_sys->p_prev_s16_buff) delete [] (p_sys->p_prev_s16_buff);
p_sys->p_prev_s16_buff = new int16_t [nb_samples * p_sys->i_channels];
if (!p_sys->p_prev_s16_buff)
goto release;
p_sys->i_prev_nb_samples = nb_samples;
}
p_buffs = p_s16_buff = p_sys->p_prev_s16_buff;
/* Convert the buffer to int16_t */
for (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(out_samples, p_sys->wind_param, &wind_ctx)) {
LOGE("unable to initialize FFT window...");
goto release;
}
p_buffs = p_s16_buff;
for (i = 0 ; i < out_samples; i++)
{
p_output[i] = 0;
p_buffer1[i] = *p_buffs;
p_buffs += p_sys->i_channels;
if (p_buffs >= &p_s16_buff[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 < out_samples; ++i) {
int16_t temp = p_output[i] * (2 ^ 16)
/ ((out_samples / 2 * 32768) ^ 2);
p_sys->output[i] = temp & 0xFF;
}
release:
window_close(&wind_ctx);
fft_close(p_state);
}
int doFft(uint8_t *fft, const uint8_t *waveform, int mCaptureSize)
{
int32_t workspace[mCaptureSize >> 1];
int32_t nonzero = 0;
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
workspace[i >> 1] =
((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
nonzero |= workspace[i >> 1];
}
if (nonzero) {
fixed_fft_real(mCaptureSize >> 1, workspace);
}
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
short tmp = workspace[i >> 1] >> 21;
while (tmp > 127 || tmp < -128) tmp >>= 1;
fft[i] = tmp;
tmp = workspace[i >> 1];
tmp >>= 5;
while (tmp > 127 || tmp < -128) tmp >>= 1;
fft[i + 1] = tmp;
}
return 0;
}
void fft_fixed(filter_sys_t *p_sys)
{
int nb_samples = p_sys->nb_samples;
int out_samples = p_sys->out_samples;
DEFINE_WIND_CONTEXT(wind_ctx);
if (!nb_samples) {
LOGE("no samples yet...");
goto release;
}
if (!window_init(out_samples, p_sys->wind_param, &wind_ctx)) {
LOGE("unable to initialize FFT window...");
goto release;
}
window_scale_in_place ((int16_t *) (p_sys->data), &wind_ctx);
doFft((uint8_t *) p_sys->output, p_sys->data, out_samples);
release:
window_close(&wind_ctx);
}
void fft_once(filter_sys_t *p_sys)
{
#ifdef FIXED_FFT
fft_fixed(p_sys);
#else
fft_float(p_sys);
#endif
}

@ -1,66 +0,0 @@
//
// Created by frank on 2021/8/16.
//
#ifndef EXECUTE_FFT_H
#define EXECUTE_FFT_H
#include <math.h>
#include <unistd.h>
#include "fft.h"
#include "window.h"
#include "fixed_fft.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "block_queue.h"
#define MIN_FFT_SIZE 128
#define MAX_FFT_SIZE 1024
#define FIXED_FFT 1
typedef struct
{
pthread_t thread;
vlc_queue_t queue;
bool dead;
int i_channels;
int i_prev_nb_samples;
int16_t *p_prev_s16_buff;
/* FFT window parameters */
window_param *wind_param;
uint8_t *data;
int data_size;
int nb_samples;
int8_t *output;
int out_samples;
} filter_sys_t;
static void *fft_thread(void *);
int open_visualizer(filter_sys_t *p_sys);
block_t *filter_audio(filter_sys_t *p_sys, void *p_in_buf);
void close_visualizer(filter_sys_t *p_filter);
void fft_once(filter_sys_t *p_sys);
int init_visualizer(filter_sys_t *p_sys);
void release_visualizer(filter_sys_t *p_sys);
void fft_float(filter_sys_t *p_sys);
void fft_fixed(filter_sys_t *p_sys);
#ifdef __cplusplus
}
#endif
#endif //EXECUTE_FFT_H

@ -0,0 +1,220 @@
//
// Created by frank on 2021/8/16.
//
#include "frank_visualizer.h"
#include <android/log.h>
#define LOG_TAG "frank_visualizer"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
__VA_ARGS__))
void short_to_float_array (const short *in, float *out, int len) {
for (int i = 0; i < len; ++i) {
out [i] = (float) (in [i] / (1.0 * 0x8000)) ;
}
}
// float FFT algorithm
void fft_float(filter_sys_t *p_sys) {
int nb_samples = p_sys->nb_samples;
int out_samples = p_sys->out_samples;
fft_state *p_state = nullptr; /* internal FFT data */
DEFINE_WIND_CONTEXT(wind_ctx); /* internal window data */
unsigned i;
float p_output[out_samples]; /* Raw FFT Result */
int16_t p_buffer1[out_samples]; /* Buffer on which we perform the FFT*/
float *p_buffl;
if (p_sys->convert_to_float) {
float p_buff[out_samples];
short_to_float_array((const short *) p_sys->data, p_buff, out_samples);
p_buffl = p_buff;
} else {
p_buffl = (float *) (p_sys->data);
}
int16_t *p_buffs; /* int16_t converted buffer */
int16_t *p_s16_buff; /* int16_t converted buffer */
if (!nb_samples) {
LOGE("no samples yet...");
goto release;
}
/* Allocate the buffer only if the number of samples change */
if (nb_samples != p_sys->i_prev_nb_samples) {
if (p_sys->p_prev_s16_buff) delete [] (p_sys->p_prev_s16_buff);
p_sys->p_prev_s16_buff = new int16_t [nb_samples * p_sys->i_channels];
if (!p_sys->p_prev_s16_buff)
goto release;
p_sys->i_prev_nb_samples = nb_samples;
}
p_buffs = p_s16_buff = p_sys->p_prev_s16_buff;
/* Convert the buffer to int16_t */
for (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(out_samples, p_sys->wind_param, &wind_ctx)) {
LOGE("unable to initialize FFT window...");
goto release;
}
p_buffs = p_s16_buff;
for (i = 0 ; i < out_samples; i++) {
p_output[i] = 0;
p_buffer1[i] = *p_buffs;
p_buffs += p_sys->i_channels;
if (p_buffs >= &p_s16_buff[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 < out_samples; ++i) {
int16_t temp = p_output[i] * (2 ^ 16)
/ ((out_samples / 2 * 32768) ^ 2);
p_sys->output[i] = temp & 0xFF;
}
release:
window_close(&wind_ctx);
fft_close(p_state);
}
int fft_fixed_internal(uint8_t *fft, const uint8_t *waveform, int mCaptureSize) {
int32_t workspace[mCaptureSize >> 1];
int32_t nonzero = 0;
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
workspace[i >> 1] =
((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
nonzero |= workspace[i >> 1];
}
if (nonzero) {
fixed_fft_real(mCaptureSize >> 1, workspace);
}
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
short tmp = workspace[i >> 1] >> 21;
while (tmp > 127 || tmp < -128) tmp >>= 1;
fft[i] = tmp;
tmp = workspace[i >> 1];
tmp >>= 5;
while (tmp > 127 || tmp < -128) tmp >>= 1;
fft[i + 1] = tmp;
}
return 0;
}
// fixed FFT algorithm
void fft_fixed(filter_sys_t *p_sys) {
int nb_samples = p_sys->nb_samples;
int out_samples = p_sys->out_samples;
DEFINE_WIND_CONTEXT(wind_ctx);
if (!nb_samples) {
LOGE("no samples yet...");
goto release;
}
if (!window_init(out_samples, p_sys->wind_param, &wind_ctx)) {
LOGE("unable to initialize FFT window...");
goto release;
}
window_scale_in_place ((int16_t *) p_sys->data, &wind_ctx);
fft_fixed_internal((uint8_t *) p_sys->output, p_sys->data, out_samples);
release:
window_close(&wind_ctx);
}
FrankVisualizer::FrankVisualizer() {
LOGE("FrankVisualizer init...");
}
FrankVisualizer::~FrankVisualizer() {
LOGE("FrankVisualizer release...");
}
void FrankVisualizer::fft_run() {
mFftLock.lock();
filter_sys_t *p_sys = fft_context;
#ifdef FIXED_FFT
fft_fixed(p_sys);
#else
fft_float(p_sys);
#endif
mFftLock.unlock();
}
int FrankVisualizer::init_visualizer() {
fft_context = new filter_sys_t();
filter_sys_t *p_filter = fft_context;
if (!p_filter)
return -1;
p_filter->convert_to_float = false;
p_filter->i_channels = 1;
p_filter->i_prev_nb_samples = 0;
p_filter->p_prev_s16_buff = nullptr;
p_filter->data = nullptr;
p_filter->data_size = 0;
p_filter->nb_samples = 0;
#ifdef FIXED_FFT
p_filter->out_samples = 512;
#else
p_filter->out_samples = FFT_BUFFER_SIZE;
#endif
p_filter->wind_param = new window_param();
/* Fetch the FFT window parameters */
window_get_param(p_filter->wind_param);
p_filter->data_size = MAX_FFT_SIZE;
p_filter->data = new uint8_t[MAX_FFT_SIZE];
memset(p_filter->data, 0, MAX_FFT_SIZE);
p_filter->output = new int8_t[p_filter->out_samples];
memset(p_filter->output, 0, p_filter->out_samples);
return 0;
}
void FrankVisualizer::release_visualizer() {
mFftLock.lock();
filter_sys_t *p_filter = fft_context;
if (!p_filter) return;
if (p_filter->p_prev_s16_buff) {
delete [] (p_filter->p_prev_s16_buff);
}
if (p_filter->wind_param) {
delete (p_filter->wind_param);
}
if (p_filter->data) {
delete [] (p_filter->data);
}
if (p_filter->output) {
delete [] (p_filter->output);
}
delete p_filter;
mFftLock.unlock();
}

@ -0,0 +1,54 @@
//
// Created by frank on 2021/8/16.
//
#ifndef FRANK_VISUALIZER_H
#define FRANK_VISUALIZER_H
#include <math.h>
#include <mutex>
#include "fft.h"
#include "window.h"
#include "fixed_fft.h"
#define MIN_FFT_SIZE 128
#define MAX_FFT_SIZE 1024
#define FIXED_FFT 1
typedef struct
{
bool convert_to_float;
int i_channels;
int i_prev_nb_samples;
int16_t *p_prev_s16_buff;
window_param *wind_param;
uint8_t *data;
int data_size;
int nb_samples;
int8_t *output;
int out_samples;
} filter_sys_t;
class FrankVisualizer {
public:
FrankVisualizer();
~FrankVisualizer();
std::mutex mFftLock;
filter_sys_t *fft_context = nullptr;
void fft_run();
int init_visualizer();
void release_visualizer();
};
#endif //FRANK_VISUALIZER_H
Loading…
Cancel
Save