Merge branch 'master' of git://0pointer.de/pulseaudio

This commit is contained in:
Daniel Mack 2009-10-27 13:00:08 +01:00
commit 9c61465c79
3 changed files with 129 additions and 127 deletions

View file

@ -1513,6 +1513,11 @@ if test "x${HAVE_SIMPLEDB}" = "x1" ; then
ENABLE_SIMPLEDB=yes ENABLE_SIMPLEDB=yes
fi fi
ENABLE_FFTW=no
if test "x${HAVE_FFTW}" = "x1" ; then
ENABLE_FFTW=yes
fi
ENABLE_OPENSSL=no ENABLE_OPENSSL=no
if test "x${HAVE_OPENSSL}" = "x1" ; then if test "x${HAVE_OPENSSL}" = "x1" ; then
ENABLE_OPENSSL=yes ENABLE_OPENSSL=yes
@ -1563,6 +1568,7 @@ echo "
Enable tdb: ${ENABLE_TDB} Enable tdb: ${ENABLE_TDB}
Enable gdbm: ${ENABLE_GDBM} Enable gdbm: ${ENABLE_GDBM}
Enable simple database: ${ENABLE_SIMPLEDB} Enable simple database: ${ENABLE_SIMPLEDB}
Enable fftw: ${ENABLE_FFTW}
System User: ${PA_SYSTEM_USER} System User: ${PA_SYSTEM_USER}
System Group: ${PA_SYSTEM_GROUP} System Group: ${PA_SYSTEM_GROUP}

View file

@ -1033,13 +1033,13 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
if ((e = read_entry(u, name))) { if ((e = read_entry(u, name))) {
uint32_t idx; uint32_t idx;
char *devname; char *devname;
uint32_t index = PA_INVALID_INDEX; uint32_t found_index = PA_INVALID_INDEX;
if ((devname = get_name(name, "sink:"))) { if ((devname = get_name(name, "sink:"))) {
pa_sink* s; pa_sink* s;
PA_IDXSET_FOREACH(s, u->core->sinks, idx) { PA_IDXSET_FOREACH(s, u->core->sinks, idx) {
if (strcmp(s->name, devname) == 0) { if (strcmp(s->name, devname) == 0) {
index = s->index; found_index = s->index;
break; break;
} }
} }
@ -1048,7 +1048,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
pa_source* s; pa_source* s;
PA_IDXSET_FOREACH(s, u->core->sources, idx) { PA_IDXSET_FOREACH(s, u->core->sources, idx) {
if (strcmp(s->name, devname) == 0) { if (strcmp(s->name, devname) == 0) {
index = s->index; found_index = s->index;
break; break;
} }
} }
@ -1058,7 +1058,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
pa_tagstruct_puts(reply, name); pa_tagstruct_puts(reply, name);
pa_tagstruct_puts(reply, e->description); pa_tagstruct_puts(reply, e->description);
pa_tagstruct_puts(reply, e->icon); pa_tagstruct_puts(reply, e->icon);
pa_tagstruct_putu32(reply, index); pa_tagstruct_putu32(reply, found_index);
pa_tagstruct_putu32(reply, NUM_ROLES); pa_tagstruct_putu32(reply, NUM_ROLES);
for (uint32_t i = ROLE_NONE; i < NUM_ROLES; ++i) { for (uint32_t i = ROLE_NONE; i < NUM_ROLES; ++i) {

242
src/modules/module-equalizer-sink.c Executable file → Normal file
View file

@ -337,7 +337,7 @@ static void sink_set_mute_cb(pa_sink *s) {
pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted); pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
} }
#ifndef __SSE2__
//reference implementation //reference implementation
static void dsp_logic( static void dsp_logic(
float * restrict dst,//used as a temp array too, needs to be fft_length! float * restrict dst,//used as a temp array too, needs to be fft_length!
@ -351,12 +351,12 @@ static void dsp_logic(
fftwf_complex * restrict output_window,//The transformed window'd src fftwf_complex * restrict output_window,//The transformed window'd src
struct userdata *u){ struct userdata *u){
//use a linear-phase sliding STFT and overlap-add method (for each channel) //use a linear-phase sliding STFT and overlap-add method (for each channel)
//zero padd the data
memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
//window the data //window the data
for(size_t j = 0; j < u->window_size; ++j){ for(size_t j = 0; j < u->window_size; ++j){
dst[j] = X * W[j] * src[j]; dst[j] = X * W[j] * src[j];
} }
//zero padd the the remaining fft window
memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
//Processing is done here! //Processing is done here!
//do fft //do fft
fftwf_execute_dft_r2c(u->forward_plan, dst, output_window); fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
@ -390,112 +390,104 @@ static void dsp_logic(
(u->samples_gathered - u->R) * sizeof(float) (u->samples_gathered - u->R) * sizeof(float)
); );
} }
#else
typedef float v4sf __attribute__ ((__aligned__(v_size * sizeof(float)))); typedef float v4sf __attribute__ ((__aligned__(v_size * sizeof(float))));
typedef union float_vector { typedef union float_vector {
float f[v_size]; float f[v_size];
v4sf v; v4sf v;
#ifdef __SSE2__
__m128 m; __m128 m;
#endif
} float_vector_t; } float_vector_t;
////regardless of sse enabled, the loops in here assume //regardless of sse enabled, the loops in here assume
////16 byte aligned addresses and memory allocations divisible by v_size //16 byte aligned addresses and memory allocations divisible by v_size
//void dsp_logic( static void dsp_logic(
// float * restrict dst,//used as a temp array too, needs to be fft_length! float * restrict dst,//used as a temp array too, needs to be fft_length!
// float * restrict src,/*input data w/ overlap at start, float * restrict src,/*input data w/ overlap at start,
// *automatically cycled in routine *automatically cycled in routine
// */ */
// float * restrict overlap,//The size of the overlap float * restrict overlap,//The size of the overlap
// const float X,//multipliar const float X,//multipliar
// const float * restrict H,//The freq. magnitude scalers filter const float * restrict H,//The freq. magnitude scalers filter
// const float * restrict W,//The windowing function const float * restrict W,//The windowing function
// fftwf_complex * restrict output_window,//The transformed window'd src fftwf_complex * restrict output_window,//The transformed window'd src
// struct userdata *u){//Collection of constants struct userdata *u){//Collection of constants
//float_vector_t x = {X, X, X, X}; const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size);
// const size_t window_size = PA_ROUND_UP(u->window_size,v_size);
// const size_t fft_h = PA_ROUND_UP(FILTER_SIZE, v_size / 2);
// //const size_t R = PA_ROUND_UP(u->R, v_size); //assert(u->samples_gathered >= u->R);
// const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size); //use a linear-phase sliding STFT and overlap-add method
// overlap_size = PA_ROUND_UP(u->overlap_size, v_size); for(size_t j = 0; j < u->window_size; j += v_size){
// //dst[j] = W[j] * src[j];
// //assert(u->samples_gathered >= u->R); float_vector_t *d = (float_vector_t*) (dst + j);
// //zero out the bit beyond the real overlap so we don't add garbage float_vector_t *w = (float_vector_t*) (W + j);
// for(size_t j = overlap_size; j > u->overlap_size; --j){ float_vector_t *s = (float_vector_t*) (src + j);
// overlap[j-1] = 0;
// }
// //use a linear-phase sliding STFT and overlap-add method
// //zero padd the data
// memset(dst + u->window_size, 0, (u->fft_size - u->window_size)*sizeof(float));
// //window the data
// for(size_t j = 0; j < window_size; j += v_size){
// //dst[j] = W[j]*src[j];
// float_vector_t *d = (float_vector_t*) (dst+j);
// float_vector_t *w = (float_vector_t*) (W+j);
// float_vector_t *s = (float_vector_t*) (src+j);
//#if __SSE2__ //#if __SSE2__
// d->m = _mm_mul_ps(x->m, _mm_mul_ps(w->m, s->m)); d->m = _mm_mul_ps(w->m, s->m);
//#else //#else
// d->v = x->v * w->v * s->v; // d->v = w->v * s->v;
//#endif //#endif
// } }
// //Processing is done here! //zero padd the the remaining fft window
// //do fft memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
// fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
// //Processing is done here!
// //do fft
// //perform filtering - purely magnitude based fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
// for(size_t j = 0;j < fft_h; j+=v_size/2){ //perform filtering - purely magnitude based
// //output_window[j][0]*=H[j]; for(size_t j = 0; j < FILTER_SIZE; j += v_size / 2){
// //output_window[j][1]*=H[j]; //output_window[j][0]*=H[j];
// float_vector_t *d = (float_vector_t*)(output_window+j); //output_window[j][1]*=H[j];
// float_vector_t h; float_vector_t *d = (float_vector_t*)( ((float *) output_window) + 2 * j);
// h.f[0] = h.f[1] = H[j]; float_vector_t h;
// h.f[2] = h.f[3] = H[j+1]; h.f[0] = h.f[1] = H[j];
h.f[2] = h.f[3] = H[j + 1];
//#if __SSE2__ //#if __SSE2__
// d->m = _mm_mul_ps(d->m, h.m); d->m = _mm_mul_ps(d->m, h.m);
//#else //#else
// d->v = d->v*h->v; // d->v = d->v * h.v;
//#endif //#endif
// } }
// //inverse fft
// fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst); //inverse fft
// fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
// ////debug: tests overlaping add
// ////and negates ALL PREVIOUS processing ////debug: tests overlaping add
// ////yields a perfect reconstruction if COLA is held ////and negates ALL PREVIOUS processing
// //for(size_t j = 0; j < u->window_size; ++j){ ////yields a perfect reconstruction if COLA is held
// // dst[j] = W[j]*src[j]; //for(size_t j = 0; j < u->window_size; ++j){
// //} // dst[j] = W[j] * src[j];
// //}
// //overlap add and preserve overlap component from this window (linear phase)
// for(size_t j = 0; j < overlap_size; j+=v_size){ //overlap add and preserve overlap component from this window (linear phase)
// //dst[j]+=overlap[j]; for(size_t j = 0; j < overlap_size; j += v_size){
// //overlap[j]+=dst[j+R]; //dst[j]+=overlap[j];
// float_vector_t *d = (float_vector_t*)(dst+j); //overlap[j]+=dst[j+R];
// float_vector_t *o = (float_vector_t*)(overlap+j); float_vector_t *d = (float_vector_t*)(dst + j);
float_vector_t *o = (float_vector_t*)(overlap + j);
//#if __SSE2__ //#if __SSE2__
// d->m = _mm_add_ps(d->m, o->m); d->m = _mm_add_ps(d->m, o->m);
// o->m = ((float_vector_t*)(dst+u->R+j))->m; o->m = ((float_vector_t*)(dst + u->R + j))->m;
//#else //#else
// d->v = d->v+o->v; // d->v = d->v + o->v;
// o->v = ((float_vector_t*)(dst+u->R+j))->v; // o->v = ((float_vector_t*)(dst + u->R + j))->v;
//#endif //#endif
// } }
// //memcpy(overlap, dst+u->R, u->overlap_size*sizeof(float)); //memcpy(overlap, dst+u->R, u->overlap_size * sizeof(float)); //overlap preserve (debug)
// //zero out the bit beyond the real overlap so we don't add garbage next iteration
// //////debug: tests if basic buffering works memset(overlap + u->overlap_size, 0, overlap_size - u->overlap_size);
// //////shouldn't modify the signal AT ALL (beyond roundoff)
// //for(size_t j = 0; j < u->window_size; ++j){ ////debug: tests if basic buffering works
// // dst[j] = src[j]; ////shouldn't modify the signal AT ALL (beyond roundoff)
// //} //for(size_t j = 0; j < u->window_size; ++j){
// // dst[j] = src[j];
// //preseve the needed input for the next window's overlap //}
// memmove(src, src + u->R,
// u->overlap_size * sizeof(float) //preseve the needed input for the next window's overlap
// ); memmove(src, src + u->R,
//} (u->samples_gathered - u->R) * sizeof(float)
);
}
#endif
static void process_samples(struct userdata *u, pa_memchunk *tchunk){ static void process_samples(struct userdata *u, pa_memchunk *tchunk){
size_t fs = pa_frame_size(&(u->sink->sample_spec)); size_t fs = pa_frame_size(&(u->sink->sample_spec));
@ -685,7 +677,7 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
//invalidate the output q //invalidate the output q
pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE); pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
pa_log("Resetting filter"); pa_log("Resetting filter");
reset_filter(u); //reset_filter(u); //this is the "proper" thing to do...
} }
} }
@ -814,33 +806,35 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
static void pack(char **strs, size_t len, char **packed, size_t *length){ static void pack(char **strs, size_t len, char **packed, size_t *length){
size_t t_len = 0; size_t t_len = 0;
size_t headers = (1+len) * sizeof(uint16_t); size_t headers = (1+len) * sizeof(uint16_t);
size_t offset = sizeof(uint16_t); char *p;
for(size_t i = 0; i < len; ++i){ for(size_t i = 0; i < len; ++i){
t_len += strlen(strs[i]); t_len += strlen(strs[i]);
} }
*length = headers + t_len; *length = headers + t_len;
*packed = pa_xmalloc0(*length); p = *packed = pa_xmalloc0(*length);
((uint16_t *) *packed)[0] = (uint16_t) len; *((uint16_t *) p) = (uint16_t) len;
p += sizeof(uint16_t);
for(size_t i = 0; i < len; ++i){ for(size_t i = 0; i < len; ++i){
uint16_t l = strlen(strs[i]); uint16_t l = strlen(strs[i]);
*((uint16_t *)(*packed + offset)) = l; *((uint16_t *) p) = (uint16_t) l;
offset += sizeof(uint16_t); p += sizeof(uint16_t);
memcpy(*packed + offset, strs[i], l); memcpy(p, strs[i], l);
offset += l; p += l;
} }
} }
static void unpack(char *str, size_t length, char ***strs, size_t *len){ static void unpack(char *str, size_t length, char ***strs, size_t *len){
size_t offset = sizeof(uint16_t); char *p = str;
*len = ((uint16_t *)str)[0]; *len = *((uint16_t *) p);
p += sizeof(uint16_t);
*strs = pa_xnew(char *, *len); *strs = pa_xnew(char *, *len);
for(size_t i = 0; i < *len; ++i){ for(size_t i = 0; i < *len; ++i){
size_t l = *((uint16_t *)(str+offset)); size_t l = *((uint16_t *) p);
size_t e = PA_MIN(offset + l, length) - offset; p += sizeof(uint16_t);
offset = PA_MIN(offset + sizeof(uint16_t), length); (*strs)[i] = pa_xnew(char, l + 1);
(*strs)[i] = pa_xnew(char, e + 1); memcpy((*strs)[i], p, l);
memcpy((*strs)[i], str + offset, e); (*strs)[i][l] = '\0';
(*strs)[i][e] = '\0'; p += l;
offset += l;
} }
} }
static void save_profile(struct userdata *u, size_t channel, char *name){ static void save_profile(struct userdata *u, size_t channel, char *name){
@ -885,17 +879,17 @@ static void save_state(struct userdata *u){
pack(u->base_profiles, u->channels, &packed, &packed_length); pack(u->base_profiles, u->channels, &packed, &packed_length);
state = (float *) pa_xmalloc0(filter_state_size + packed_length); state = (float *) pa_xmalloc0(filter_state_size + packed_length);
memcpy(state + FILTER_STATE_SIZE, packed, packed_length);
pa_xfree(packed);
for(size_t c = 0; c < u->channels; ++c){ for(size_t c = 0; c < u->channels; ++c){
a_i = pa_aupdate_read_begin(u->a_H[c]); a_i = pa_aupdate_read_begin(u->a_H[c]);
state[c * CHANNEL_PROFILE_SIZE] = u->Xs[a_i][c]; state[c * CHANNEL_PROFILE_SIZE] = u->Xs[c][a_i];
H = u->Hs[c][a_i]; H = u->Hs[c][a_i];
H_n = state + c * CHANNEL_PROFILE_SIZE + 1; H_n = &state[c * CHANNEL_PROFILE_SIZE + 1];
memcpy(H_n, H, FILTER_SIZE * sizeof(float)); memcpy(H_n, H, FILTER_SIZE * sizeof(float));
pa_aupdate_read_end(u->a_H[c]); pa_aupdate_read_end(u->a_H[c]);
} }
memcpy(((char *)state) + filter_state_size, packed, packed_length);
pa_xfree(packed);
key.data = state_name; key.data = state_name;
key.size = strlen(key.data); key.size = strlen(key.data);
@ -978,13 +972,13 @@ static void load_state(struct userdata *u){
memcpy(u->Hs[c][a_i], H, FILTER_SIZE * sizeof(float)); memcpy(u->Hs[c][a_i], H, FILTER_SIZE * sizeof(float));
pa_aupdate_write_end(u->a_H[c]); pa_aupdate_write_end(u->a_H[c]);
} }
//unpack(((char *)value.data) + FILTER_STATE_SIZE, value.size - FILTER_STATE_SIZE, &names, &n_profs); unpack(((char *)value.data) + FILTER_STATE_SIZE * sizeof(float), value.size - FILTER_STATE_SIZE * sizeof(float), &names, &n_profs);
//n_profs = PA_MIN(n_profs, u->channels); n_profs = PA_MIN(n_profs, u->channels);
//for(size_t c = 0; c < n_profs; ++c){ for(size_t c = 0; c < n_profs; ++c){
// pa_xfree(u->base_profiles[c]); pa_xfree(u->base_profiles[c]);
// u->base_profiles[c] = names[c]; u->base_profiles[c] = names[c];
//} }
//pa_xfree(names); pa_xfree(names);
} }
pa_datum_free(&value); pa_datum_free(&value);
}else{ }else{
@ -1062,9 +1056,12 @@ int pa__init(pa_module*m) {
pa_modargs_get_value_boolean(ma, "set_default", &u->set_default); pa_modargs_get_value_boolean(ma, "set_default", &u->set_default);
u->channels = ss.channels; u->channels = ss.channels;
u->fft_size = pow(2, ceil(log(ss.rate)/log(2)));//probably unstable near corner cases of powers of 2 u->fft_size = pow(2, ceil(log(ss.rate) / log(2)));//probably unstable near corner cases of powers of 2
pa_log_debug("fft size: %ld", u->fft_size); pa_log_debug("fft size: %ld", u->fft_size);
u->window_size = 15999; u->window_size = 15999;
if(u->window_size % 2 == 0){
u->window_size--;
}
u->R = (u->window_size + 1) / 2; u->R = (u->window_size + 1) / 2;
u->overlap_size = u->window_size - u->R; u->overlap_size = u->window_size - u->R;
u->samples_gathered = 0; u->samples_gathered = 0;
@ -1088,7 +1085,6 @@ int pa__init(pa_module*m) {
u->a_H[c] = pa_aupdate_new(); u->a_H[c] = pa_aupdate_new();
u->input[c] = NULL; u->input[c] = NULL;
u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float)); u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float));
memset(u->overlap_accum[c], 0, u->overlap_size*sizeof(float));
} }
u->output_window = alloc((FILTER_SIZE), sizeof(fftwf_complex)); u->output_window = alloc((FILTER_SIZE), sizeof(fftwf_complex));
u->forward_plan = fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE); u->forward_plan = fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE);