/* Initialization and runtime control */ static int control(struct af_instance *af, int cmd, void* arg) { af_hrtf_t *s = af->priv; int test_output_res; switch(cmd) { case AF_CONTROL_REINIT: reset(s); af->data->rate = 48000; mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch); if(af->data->nch == 2) { /* 2 channel input */ if(s->decode_mode != HRTF_MIX_MATRIX2CH) { /* Default behavior is stereo mixing. */ s->decode_mode = HRTF_MIX_STEREO; } } else if (af->data->nch < 5) { mp_audio_set_channels_old(af->data, 5); } mp_audio_set_format(af->data, AF_FORMAT_S16); test_output_res = af_test_output(af, (struct mp_audio*)arg); // after testing input set the real output format mp_audio_set_num_channels(af->data, 2); s->print_flag = 1; return test_output_res; case AF_CONTROL_RESET: reset(s); return AF_OK; } return AF_UNKNOWN; }
/* Initialization and runtime control */ static int control(struct af_instance *af, int cmd, void* arg) { af_hrtf_t *s = af->setup; int test_output_res; char mode; switch(cmd) { case AF_CONTROL_REINIT: af->data->rate = ((struct mp_audio*)arg)->rate; if(af->data->rate != 48000) { // automatic samplerate adjustment in the filter chain // is not yet supported. mp_msg(MSGT_AFILTER, MSGL_ERR, "[hrtf] ERROR: Sampling rate is not 48000 Hz (%d)!\n", af->data->rate); return AF_ERROR; } mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch); if(af->data->nch == 2) { /* 2 channel input */ if(s->decode_mode != HRTF_MIX_MATRIX2CH) { /* Default behavior is stereo mixing. */ s->decode_mode = HRTF_MIX_STEREO; } } else if (af->data->nch < 5) mp_audio_set_channels_old(af->data, 5); mp_audio_set_format(af->data, AF_FORMAT_S16); test_output_res = af_test_output(af, (struct mp_audio*)arg); // after testing input set the real output format mp_audio_set_num_channels(af->data, 2); s->print_flag = 1; return test_output_res; case AF_CONTROL_COMMAND_LINE: sscanf((char*)arg, "%c", &mode); switch(mode) { case 'm': /* Use matrix rear decoding. */ s->matrix_mode = 1; break; case 's': /* Input needs matrix decoding. */ s->decode_mode = HRTF_MIX_MATRIX2CH; break; case '0': s->matrix_mode = 0; break; default: mp_msg(MSGT_AFILTER, MSGL_ERR, "[hrtf] Mode is neither 'm', 's', nor '0' (%c).\n", mode); return AF_ERROR; } s->print_flag = 1; return AF_OK; } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { af_sub_t* s = af->setup; switch(cmd){ case AF_CONTROL_REINIT:{ // Sanity check if(!arg) return AF_ERROR; af->data->rate = ((struct mp_audio*)arg)->rate; mp_audio_set_channels_old(af->data, MPMAX(s->ch+1,((struct mp_audio*)arg)->nch)); mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE); // Design low-pass filter s->k = 1.0; if((-1 == af_filter_szxform(sp[0].a, sp[0].b, Q, s->fc, (float)af->data->rate, &s->k, s->w[0])) || (-1 == af_filter_szxform(sp[1].a, sp[1].b, Q, s->fc, (float)af->data->rate, &s->k, s->w[1]))) return AF_ERROR; return af_test_output(af,(struct mp_audio*)arg); } case AF_CONTROL_COMMAND_LINE:{ int ch=5; float fc=60.0; sscanf(arg,"%f:%i", &fc , &ch); if(AF_OK != control(af,AF_CONTROL_SUB_CH | AF_CONTROL_SET, &ch)) return AF_ERROR; return control(af,AF_CONTROL_SUB_FC | AF_CONTROL_SET, &fc); } case AF_CONTROL_SUB_CH | AF_CONTROL_SET: // Requires reinit // Sanity check if((*(int*)arg >= AF_NCH) || (*(int*)arg < 0)){ mp_msg(MSGT_AFILTER, MSGL_ERR, "[sub] Subwoofer channel number must be between " " 0 and %i current value is %i\n", AF_NCH-1, *(int*)arg); return AF_ERROR; } s->ch = *(int*)arg; return AF_OK; case AF_CONTROL_SUB_CH | AF_CONTROL_GET: *(int*)arg = s->ch; return AF_OK; case AF_CONTROL_SUB_FC | AF_CONTROL_SET: // Requires reinit // Sanity check if((*(float*)arg > 300) || (*(float*)arg < 20)){ mp_msg(MSGT_AFILTER, MSGL_ERR, "[sub] Cutoff frequency must be between 20Hz and" " 300Hz current value is %0.2f",*(float*)arg); return AF_ERROR; } // Set cutoff frequency s->fc = *(float*)arg; return AF_OK; case AF_CONTROL_SUB_FC | AF_CONTROL_GET: *(float*)arg = s->fc; return AF_OK; } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { af_surround_t *s = af->setup; switch(cmd){ case AF_CONTROL_REINIT:{ float fc; mp_audio_copy_config(af->data, (struct mp_audio*)arg); mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch*2); mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE); if (af->data->nch != 4){ mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Only stereo input is supported.\n"); return AF_DETACH; } // Surround filer coefficients fc = 2.0 * 7000.0/(float)af->data->rate; if (-1 == af_filter_design_fir(L, s->w, &fc, LP|HAMMING, 0)){ mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Unable to design low-pass filter.\n"); return AF_ERROR; } // Free previous delay queues free(s->dl); free(s->dr); // Allocate new delay queues s->dl = calloc(LD,af->data->bps); s->dr = calloc(LD,af->data->bps); if((NULL == s->dl) || (NULL == s->dr)) mp_msg(MSGT_AFILTER, MSGL_FATAL, "[delay] Out of memory\n"); // Initialize delay queue index if(AF_OK != af_from_ms(1, &s->d, &s->wi, af->data->rate, 0.0, 1000.0)) return AF_ERROR; // printf("%i\n",s->wi); s->ri = 0; if((af->data->format != ((struct mp_audio*)arg)->format) || (af->data->bps != ((struct mp_audio*)arg)->bps)){ mp_audio_set_format((struct mp_audio*)arg, af->data->format); return AF_FALSE; } return AF_OK; } case AF_CONTROL_COMMAND_LINE:{ float d = 0; sscanf((char*)arg,"%f",&d); if ((d < 0) || (d > 1000)){ mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Invalid delay time, valid time values" " are 0ms to 1000ms current value is %0.3f ms\n",d); return AF_ERROR; } s->d = d; return AF_OK; } } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { af_center_t* s = af->priv; switch(cmd){ case AF_CONTROL_REINIT:{ // Sanity check if(!arg) return AF_ERROR; af->data->rate = ((struct mp_audio*)arg)->rate; mp_audio_set_channels_old(af->data, MPMAX(s->ch+1,((struct mp_audio*)arg)->nch)); mp_audio_set_format(af->data, AF_FORMAT_FLOAT); return af_test_output(af,(struct mp_audio*)arg); } } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { af_surround_t *s = af->priv; switch(cmd){ case AF_CONTROL_REINIT:{ struct mp_audio *in = arg; float fc; if (!mp_chmap_is_stereo(&in->channels)) { MP_ERR(af, "Only stereo input is supported.\n"); return AF_DETACH; } mp_audio_set_format(in, AF_FORMAT_FLOAT); mp_audio_copy_config(af->data, in); mp_audio_set_channels_old(af->data, in->nch * 2); // Surround filer coefficients fc = 2.0 * 7000.0/(float)af->data->rate; if (-1 == af_filter_design_fir(L, s->w, &fc, LP|HAMMING, 0)){ MP_ERR(af, "Unable to design low-pass filter.\n"); return AF_ERROR; } // Free previous delay queues free(s->dl); free(s->dr); // Allocate new delay queues s->dl = calloc(LD,af->data->bps); s->dr = calloc(LD,af->data->bps); if((NULL == s->dl) || (NULL == s->dr)) MP_FATAL(af, "Out of memory\n"); // Initialize delay queue index if(AF_OK != af_from_ms(1, &s->d, &s->wi, af->data->rate, 0.0, 1000.0)) return AF_ERROR; // printf("%i\n",s->wi); s->ri = 0; return AF_OK; } } return AF_UNKNOWN; }
// Filter data through filter static int filter(struct af_instance* af, struct mp_audio* data, int flags){ af_surround_t* s = (af_surround_t*)af->priv; const float* m = steering_matrix[0]; float* in = data->planes[0]; // Input audio data float* out = NULL; // Output audio data float* end = in + data->samples * data->nch; int i = s->i; // Filter queue index int ri = s->ri; // Read index for delay queue int wi = s->wi; // Write index for delay queue mp_audio_realloc_min(af->data, data->samples); out = af->data->planes[0]; while(in < end){ /* Dominance: abs(in[0]) abs(in[1]); abs(in[0]+in[1]) abs(in[0]-in[1]); 10 * log( abs(in[0]) / (abs(in[1])|1) ); 10 * log( abs(in[0]+in[1]) / (abs(in[0]-in[1])|1) ); */ /* About volume balancing... Surround encoding does the following: Lt=L+.707*C+.707*S, Rt=R+.707*C-.707*S So S should be extracted as: (Lt-Rt) But we are splitting the S to two output channels, so we must take 3dB off as we split it: Ls=Rs=.707*(Lt-Rt) Trouble is, Lt could be +1, Rt -1, so possibility that S will overflow. So to avoid that, we cut L/R by 3dB (*.707), and S by 6dB (/2). This keeps the overall balance, but guarantees no overflow. */ // Output front left and right out[0] = m[0]*in[0] + m[1]*in[1]; out[1] = m[2]*in[0] + m[3]*in[1]; // Low-pass output @ 7kHz FIR((&s->lq[i]), s->w, s->dl[wi]); // Delay output by d ms out[2] = s->dl[ri]; #ifdef SPLITREAR // Low-pass output @ 7kHz FIR((&s->rq[i]), s->w, s->dr[wi]); // Delay output by d ms out[3] = s->dr[ri]; #else out[3] = -out[2]; #endif // Update delay queues indexes UPDATEQI(ri); UPDATEQI(wi); // Calculate and save surround in circular queue #ifdef SPLITREAR ADDQUE(i, s->rq, s->lq, m[6]*in[0]+m[7]*in[1], m[8]*in[0]+m[9]*in[1]); #else ADDQUE(i, s->lq, m[4]*in[0]+m[5]*in[1]); #endif // Next sample... in = &in[data->nch]; out = &out[af->data->nch]; } // Save indexes s->i = i; s->ri = ri; s->wi = wi; // Set output data data->planes[0] = af->data->planes[0]; mp_audio_set_channels_old(data, af->data->nch); return 0; }