// Initialization and runtime control static int control(struct af_instance_s* 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 = ((af_data_t*)arg)->rate; af->data->nch = max(s->ch+1,((af_data_t*)arg)->nch); af->data->format = AF_FORMAT_FLOAT_NE; af->data->bps = 4; // 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,(af_data_t*)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)){ af_msg(AF_MSG_ERROR,"[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)){ af_msg(AF_MSG_ERROR,"[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; }
// Filter data through filter static af_data_t* play(struct af_instance_s* af, af_data_t* data) { // Do something necessary to get rid of annoying warning during compile if(!af) af_msg(AF_MSG_ERROR,"EEEK: Argument af == NULL in af_dummy.c play()."); return data; }
// Filter data through filter static af_data_t* play_s16(struct af_instance_s* af, af_data_t* data) { af_sinesuppress_t *s = af->setup; register int i = 0; int16_t *a = (int16_t*)data->audio; // Audio data int len = data->len/2; // Number of samples for (i = 0; i < len; i++) { double co= cos(s->pos); double si= sin(s->pos); s->real += co * a[i]; s->imag += si * a[i]; s->ref += co * co; a[i] -= (s->real * co + s->imag * si) / s->ref; s->real -= s->real * s->decay; s->imag -= s->imag * s->decay; s->ref -= s->ref * s->decay; s->pos += 2 * M_PI * s->freq / data->rate; } af_msg(AF_MSG_VERBOSE,"[sinesuppress] f:%8.2f: amp:%8.2f\n", s->freq, sqrt(s->real*s->real + s->imag*s->imag) / s->ref); return data; }
// Make sure the routes are sane static int check_routes(af_channels_t* s, int nin, int nout) { int i; if((s->nr < 1) || (s->nr > AF_NCH)){ af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs must be" " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); return AF_ERROR; } for(i=0;i<s->nr;i++){ if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){ af_msg(AF_MSG_ERROR,"[channels] Invalid routing in pair nr. %i.\n", i); return AF_ERROR; } } return AF_OK; }
// Sanity check for bytes per sample static int check_bps(int bps) { if(bps != 4 && bps != 3 && bps != 2 && bps != 1){ af_msg(AF_MSG_ERROR,"[format] The number of bytes per sample" " must be 1, 2, 3 or 4. Current value is %i \n",bps); return AF_ERROR; } return AF_OK; }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { switch(cmd) { case AF_CONTROL_REINIT: memcpy(af->data,(af_data_t*)arg,sizeof(af_data_t)); af_msg(AF_MSG_VERBOSE,"[dummy] Was reinitialized: %iHz/%ich/%s\n", af->data->rate,af->data->nch,af_fmt2str_short(af->data->format)); return AF_OK; } return AF_UNKNOWN; }
// Check for unsupported formats static int check_format(int format) { char buf[256]; switch(format & AF_FORMAT_SPECIAL_MASK){ case(AF_FORMAT_IMA_ADPCM): case(AF_FORMAT_MPEG2): case(AF_FORMAT_AC3): af_msg(AF_MSG_ERROR,"[format] Sample format %s not yet supported \n", af_fmt2str(format,buf,256)); return AF_ERROR; } return AF_OK; }
// Local function for copying data static void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps) { switch(bps){ case 1:{ int8_t* tin = (int8_t*)in; int8_t* tout = (int8_t*)out; tin += inos; tout += outos; len = len/ins; while(len--){ *tout=*tin; tin +=ins; tout+=outs; } break; } case 2:{ int16_t* tin = (int16_t*)in; int16_t* tout = (int16_t*)out; tin += inos; tout += outos; len = len/(2*ins); while(len--){ *tout=*tin; tin +=ins; tout+=outs; } break; } case 3:{ int8_t* tin = (int8_t*)in; int8_t* tout = (int8_t*)out; tin += 3 * inos; tout += 3 * outos; len = len / ( 3 * ins); while (len--) { tout[0] = tin[0]; tout[1] = tin[1]; tout[2] = tin[2]; tin += 3 * ins; tout += 3 * outs; } break; } case 4:{ int32_t* tin = (int32_t*)in; int32_t* tout = (int32_t*)out; tin += inos; tout += outos; len = len/(4*ins); while(len--){ *tout=*tin; tin +=ins; tout+=outs; } break; } case 8:{ int64_t* tin = (int64_t*)in; int64_t* tout = (int64_t*)out; tin += inos; tout += outos; len = len/(8*ins); while(len--){ *tout=*tin; tin +=ins; tout+=outs; } break; } default: af_msg(AF_MSG_ERROR,"[channels] Unsupported number of bytes/sample: %i" " please report this error on the MPlayer mailing list. \n",bps); } }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_channels_t* s = af->setup; switch(cmd){ case AF_CONTROL_REINIT: // Set default channel assignment if(!s->router){ int i; // Make sure this filter isn't redundant if(af->data->nch == ((af_data_t*)arg)->nch) return AF_DETACH; // If mono: fake stereo if(((af_data_t*)arg)->nch == 1){ s->nr = min(af->data->nch,2); for(i=0;i<s->nr;i++){ s->route[i][FR] = 0; s->route[i][TO] = i; } } else{ s->nr = min(af->data->nch, ((af_data_t*)arg)->nch); for(i=0;i<s->nr;i++){ s->route[i][FR] = i; s->route[i][TO] = i; } } } af->data->rate = ((af_data_t*)arg)->rate; af->data->format = ((af_data_t*)arg)->format; af->data->bps = ((af_data_t*)arg)->bps; af->mul.n = af->data->nch; af->mul.d = ((af_data_t*)arg)->nch; af_frac_cancel(&af->mul); return check_routes(s,((af_data_t*)arg)->nch,af->data->nch); case AF_CONTROL_COMMAND_LINE:{ int nch = 0; int n = 0; // Check number of channels and number of routing pairs sscanf(arg, "%i:%i%n", &nch, &s->nr, &n); // If router scan commandline for routing pairs if(s->nr){ char* cp = &((char*)arg)[n]; int ch = 0; // Sanity check if((s->nr < 1) || (s->nr > AF_NCH)){ af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs must be" " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); } s->router = 1; // Scan for pairs on commandline while((*cp == ':') && (ch < s->nr)){ sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n); af_msg(AF_MSG_VERBOSE,"[channels] Routing from channel %i to" " channel %i\n",s->route[ch][FR],s->route[ch][TO]); cp = &cp[n]; ch++; } } if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch)) return AF_ERROR; return AF_OK; } case AF_CONTROL_CHANNELS | AF_CONTROL_SET: // Reinit must be called after this function has been called // Sanity check if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){ af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be" " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]); return AF_ERROR; } af->data->nch=((int*)arg)[0]; if(!s->router) af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels" " to %i\n",af->data->nch); return AF_OK; case AF_CONTROL_CHANNELS | AF_CONTROL_GET: *(int*)arg = af->data->nch; return AF_OK; case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{ int ch = ((af_control_ext_t*)arg)->ch; int* route = ((af_control_ext_t*)arg)->arg; s->route[ch][FR] = route[FR]; s->route[ch][TO] = route[TO]; return AF_OK; } case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{ int ch = ((af_control_ext_t*)arg)->ch; int* route = ((af_control_ext_t*)arg)->arg; route[FR] = s->route[ch][FR]; route[TO] = s->route[ch][TO]; return AF_OK; } case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET: s->nr = *(int*)arg; return AF_OK; case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET: *(int*)arg = s->nr; return AF_OK; case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET: s->router = *(int*)arg; return AF_OK; case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET: *(int*)arg = s->router; return AF_OK; } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_delay_t* s = af->setup; switch(cmd){ case AF_CONTROL_REINIT:{ int i; // Free prevous delay queues for(i=0;i<af->data->nch;i++){ if(s->q[i]) free(s->q[i]); } af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch; af->data->format = ((af_data_t*)arg)->format; af->data->bps = ((af_data_t*)arg)->bps; // Allocate new delay queues for(i=0;i<af->data->nch;i++){ s->q[i] = calloc(L,af->data->bps); if(NULL == s->q[i]) af_msg(AF_MSG_FATAL,"[delay] Out of memory\n"); } return control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET,s->d); } case AF_CONTROL_COMMAND_LINE:{ int n = 1; int i = 0; char* cl = arg; while(n && i < AF_NCH ){ sscanf(cl,"%f:%n",&s->d[i],&n); if(n==0 || cl[n-1] == '\0') break; cl=&cl[n]; i++; } return AF_OK; } case AF_CONTROL_DELAY_LEN | AF_CONTROL_SET:{ int i; if(AF_OK != af_from_ms(AF_NCH, arg, s->wi, af->data->rate, 0.0, 1000.0)) return AF_ERROR; s->ri = 0; for(i=0;i<AF_NCH;i++){ af_msg(AF_MSG_DEBUG0,"[delay] Channel %i delayed by %0.3fms\n", i,clamp(s->d[i],0.0,1000.0)); af_msg(AF_MSG_DEBUG1,"[delay] Channel %i delayed by %i samples\n", i,s->wi[i]); } return AF_OK; } case AF_CONTROL_DELAY_LEN | AF_CONTROL_GET:{ int i; for(i=0;i<AF_NCH;i++){ if(s->ri > s->wi[i]) s->wi[i] = L - (s->ri - s->wi[i]); else s->wi[i] = s->wi[i] - s->ri; } return af_to_ms(AF_NCH, s->wi, arg, af->data->rate); } } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_scaletempo_t* s = af->setup; switch(cmd){ case AF_CONTROL_REINIT:{ af_data_t* data = (af_data_t*)arg; float srate = data->rate / 1000; int nch = data->nch; int bps; int use_int = 0; int frames_stride, frames_overlap; int i, j; af_msg(AF_MSG_VERBOSE, "[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n", s->speed, s->scale_nominal, s->scale); if (s->scale == 1.0) { if (s->speed_tempo && s->speed_pitch) return AF_DETACH; memcpy(af->data, data, sizeof(af_data_t)); return af_test_output(af, data); } af->data->rate = data->rate; af->data->nch = data->nch; if ( data->format == AF_FORMAT_S16_LE || data->format == AF_FORMAT_S16_BE ) { use_int = 1; af->data->format = AF_FORMAT_S16_NE; af->data->bps = bps = 2; } else { af->data->format = AF_FORMAT_FLOAT_NE; af->data->bps = bps = 4; } frames_stride = srate * s->ms_stride; s->bytes_stride = frames_stride * bps * nch; s->bytes_stride_scaled = s->scale * s->bytes_stride; s->frames_stride_scaled = s->scale * frames_stride; s->frames_stride_error = 0; af->mul = (double)s->bytes_stride / s->bytes_stride_scaled; frames_overlap = frames_stride * s->percent_overlap; if (frames_overlap <= 0) { s->bytes_standing = s->bytes_stride; s->samples_standing = s->bytes_standing / bps; s->output_overlap = NULL; } else { s->samples_overlap = frames_overlap * nch; s->bytes_overlap = frames_overlap * nch * bps; s->bytes_standing = s->bytes_stride - s->bytes_overlap; s->samples_standing = s->bytes_standing / bps; s->buf_overlap = realloc(s->buf_overlap, s->bytes_overlap); s->table_blend = realloc(s->table_blend, s->bytes_overlap * 4); if(!s->buf_overlap || !s->table_blend) { af_msg(AF_MSG_FATAL, "[scaletempo] Out of memory\n"); return AF_ERROR; } bzero(s->buf_overlap, s->bytes_overlap); if (use_int) { int32_t* pb = s->table_blend; int64_t blend = 0; for (i=0; i<frames_overlap; i++) { int32_t v = blend / frames_overlap; for (j=0; j<nch; j++) { *pb++ = v; } blend += 65536; // 2^16 } s->output_overlap = output_overlap_s16; } else { float* pb = s->table_blend; for (i=0; i<frames_overlap; i++) { float v = i / (float)frames_overlap; for (j=0; j<nch; j++) { *pb++ = v; } } s->output_overlap = output_overlap_float; } } s->frames_search = (frames_overlap > 1) ? srate * s->ms_search : 0; if (s->frames_search <= 0) { s->best_overlap_offset = NULL; } else { if (use_int) { int64_t t = frames_overlap; int32_t n = 8589934588LL / (t * t); // 4 * (2^31 - 1) / t^2 int32_t* pw; s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap * 2 + UNROLL_PADDING); s->table_window = realloc(s->table_window, s->bytes_overlap * 2 - nch * bps * 2); if(!s->buf_pre_corr || !s->table_window) { af_msg(AF_MSG_FATAL, "[scaletempo] Out of memory\n"); return AF_ERROR; } memset((char *)s->buf_pre_corr + s->bytes_overlap * 2, 0, UNROLL_PADDING); pw = s->table_window; for (i=1; i<frames_overlap; i++) { int32_t v = ( i * (t - i) * n ) >> 15; for (j=0; j<nch; j++) { *pw++ = v; } } s->best_overlap_offset = best_overlap_offset_s16; } else { float* pw; s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap); s->table_window = realloc(s->table_window, s->bytes_overlap - nch * bps); if(!s->buf_pre_corr || !s->table_window) { af_msg(AF_MSG_FATAL, "[scaletempo] Out of memory\n"); return AF_ERROR; } pw = s->table_window; for (i=1; i<frames_overlap; i++) { float v = i * (frames_overlap - i); for (j=0; j<nch; j++) { *pw++ = v; } } s->best_overlap_offset = best_overlap_offset_float; } } s->bytes_per_frame = bps * nch; s->num_channels = nch; s->bytes_queue = (s->frames_search + frames_stride + frames_overlap) * bps * nch; s->buf_queue = realloc(s->buf_queue, s->bytes_queue + UNROLL_PADDING); if(!s->buf_queue) { af_msg(AF_MSG_FATAL, "[scaletempo] Out of memory\n"); return AF_ERROR; } af_msg (AF_MSG_DEBUG0, "[scaletempo] " "%.2f stride_in, %i stride_out, %i standing, " "%i overlap, %i search, %i queue, %s mode\n", s->frames_stride_scaled, (int)(s->bytes_stride / nch / bps), (int)(s->bytes_standing / nch / bps), (int)(s->bytes_overlap / nch / bps), s->frames_search, (int)(s->bytes_queue / nch / bps), (use_int?"s16":"float")); return af_test_output(af, (af_data_t*)arg); } case AF_CONTROL_PLAYBACK_SPEED | AF_CONTROL_SET:{ if (s->speed_tempo) { if (s->speed_pitch) { break; } s->speed = *(float*)arg; s->scale = s->speed * s->scale_nominal; } else { if (s->speed_pitch) { s->speed = 1 / *(float*)arg; s->scale = s->speed * s->scale_nominal; break; } } return AF_OK; } case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_SET:{ s->scale = *(float*)arg; s->scale = s->speed * s->scale_nominal; return AF_OK; } case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_GET: *(float*)arg = s->scale; return AF_OK; case AF_CONTROL_COMMAND_LINE:{ strarg_t speed = {}; opt_t subopts[] = { {"scale", OPT_ARG_FLOAT, &s->scale_nominal, NULL}, {"stride", OPT_ARG_FLOAT, &s->ms_stride, NULL}, {"overlap", OPT_ARG_FLOAT, &s->percent_overlap, NULL}, {"search", OPT_ARG_FLOAT, &s->ms_search, NULL}, {"speed", OPT_ARG_STR, &speed, NULL}, {NULL}, }; if (subopt_parse(arg, subopts) != 0) { return AF_ERROR; } if (s->scale_nominal <= 0) { af_msg(AF_MSG_ERROR, "[scaletempo] " MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange ": scale > 0\n"); return AF_ERROR; } if (s->ms_stride <= 0) { af_msg(AF_MSG_ERROR, "[scaletempo] " MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange ": stride > 0\n"); return AF_ERROR; } if (s->percent_overlap < 0 || s->percent_overlap > 1) { af_msg(AF_MSG_ERROR, "[scaletempo] " MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange ": 0 <= overlap <= 1\n"); return AF_ERROR; } if (s->ms_search < 0) { af_msg(AF_MSG_ERROR, "[scaletempo] " MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange ": search >= 0\n"); return AF_ERROR; } if (speed.len > 0) { if (strcmp(speed.str, "pitch") == 0) { s->speed_tempo = 0; s->speed_pitch = 1; } else if (strcmp(speed.str, "tempo") == 0) { s->speed_tempo = 1; s->speed_pitch = 0; } else if (strcmp(speed.str, "none") == 0) { s->speed_tempo = 0; s->speed_pitch = 0; } else if (strcmp(speed.str, "both") == 0) { s->speed_tempo = 1; s->speed_pitch = 1; } else { af_msg(AF_MSG_ERROR, "[scaletempo] " MSGTR_ErrorParsingCommandLine ": " MSGTR_AF_ValueOutOfRange ": speed=[pitch|tempo|none|both]\n"); return AF_ERROR; } } s->scale = s->speed * s->scale_nominal; af_msg(AF_MSG_DEBUG0, "[scaletempo] %6.3f scale, %6.2f stride, %6.2f overlap, %6.2f search, speed = %s\n", s->scale_nominal, s->ms_stride, s->percent_overlap, s->ms_search, (s->speed_tempo?(s->speed_pitch?"tempo and speed":"tempo"):(s->speed_pitch?"pitch":"none"))); return AF_OK; } }
// Filter data through filter static af_data_t* play(struct af_instance_s* af, af_data_t* data) { af_scaletempo_t* s = af->setup; int offset_in; int max_bytes_out; int8_t* pout; if (s->scale == 1.0) { return data; } // RESIZE_LOCAL_BUFFER - can't use macro max_bytes_out = ((int)(data->len / s->bytes_stride_scaled) + 1) * s->bytes_stride; if (max_bytes_out > af->data->len) { af_msg(AF_MSG_VERBOSE, "[libaf] Reallocating memory in module %s, " "old len = %i, new len = %i\n",af->info->name,af->data->len,max_bytes_out); af->data->audio = realloc(af->data->audio, max_bytes_out); if (!af->data->audio) { af_msg(AF_MSG_FATAL, "[libaf] Could not allocate memory\n"); return NULL; } af->data->len = max_bytes_out; } offset_in = fill_queue(af, data, 0); pout = af->data->audio; while (s->bytes_queued >= s->bytes_queue) { int ti; float tf; int bytes_off = 0; // output stride if (s->output_overlap) { if (s->best_overlap_offset) bytes_off = s->best_overlap_offset(s); s->output_overlap(s, pout, bytes_off); } memcpy(pout + s->bytes_overlap, s->buf_queue + bytes_off + s->bytes_overlap, s->bytes_standing); pout += s->bytes_stride; // input stride memcpy(s->buf_overlap, s->buf_queue + bytes_off + s->bytes_stride, s->bytes_overlap); tf = s->frames_stride_scaled + s->frames_stride_error; ti = (int)tf; s->frames_stride_error = tf - ti; s->bytes_to_slide = ti * s->bytes_per_frame; offset_in += fill_queue(af, data, offset_in); } // This filter can have a negative delay when scale > 1: // output corresponding to some length of input can be decided and written // after receiving only a part of that input. af->delay = s->bytes_queued - s->bytes_to_slide; data->audio = af->data->audio; data->len = pout - (int8_t *)af->data->audio; return data; }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_surround_t *s = af->setup; switch(cmd){ case AF_CONTROL_REINIT:{ float fc; af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch*2; af->data->format = AF_FORMAT_FLOAT_NE; af->data->bps = 4; if (af->data->nch != 4){ af_msg(AF_MSG_ERROR,"[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)){ af_msg(AF_MSG_ERROR,"[surround] Unable to design low-pass filter.\n"); return AF_ERROR; } // Free previous delay queues if(s->dl) free(s->dl); if(s->dr) 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)) af_msg(AF_MSG_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 != ((af_data_t*)arg)->format) || (af->data->bps != ((af_data_t*)arg)->bps)){ ((af_data_t*)arg)->format = af->data->format; ((af_data_t*)arg)->bps = af->data->bps; return AF_FALSE; } return AF_OK; } case AF_CONTROL_COMMAND_LINE:{ float d = 0; sscanf((char*)arg,"%f",&d); if ((d < 0) || (d > 1000)){ af_msg(AF_MSG_ERROR,"[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 af audio filter instance cmd control command arg argument */ static int control(struct af_instance_s* af, int cmd, void* arg) { af_export_t* s = af->setup; switch (cmd){ case AF_CONTROL_REINIT:{ int i=0; int mapsize; // Free previous buffers if (s->buf && s->buf[0]) free(s->buf[0]); // unmap previous area if(s->mmap_area) munmap(s->mmap_area, SIZE_HEADER + (af->data->bps*s->sz*af->data->nch)); // close previous file descriptor if(s->fd) close(s->fd); // Accept only int16_t as input format (which sucks) af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch; af->data->format = AF_FORMAT_S16_NE; af->data->bps = 2; // If buffer length isn't set, set it to the default value if(s->sz == 0) s->sz = DEF_SZ; // Allocate new buffers (as one continuous block) s->buf[0] = calloc(s->sz*af->data->nch, af->data->bps); if(NULL == s->buf[0]) af_msg(AF_MSG_FATAL, "[export] Out of memory\n"); for(i = 1; i < af->data->nch; i++) s->buf[i] = s->buf[0] + i*s->sz*af->data->bps; // Init memory mapping s->fd = open(s->filename, O_RDWR | O_CREAT | O_TRUNC, 0640); af_msg(AF_MSG_INFO, "[export] Exporting to file: %s\n", s->filename); if(s->fd < 0) af_msg(AF_MSG_FATAL, "[export] Could not open/create file: %s\n", s->filename); // header + buffer mapsize = (SIZE_HEADER + (af->data->bps * s->sz * af->data->nch)); // grow file to needed size for(i = 0; i < mapsize; i++){ char null = 0; write(s->fd, (void*) &null, 1); } // mmap size s->mmap_area = mmap(0, mapsize, PROT_READ|PROT_WRITE,MAP_SHARED, s->fd, 0); if(s->mmap_area == NULL) af_msg(AF_MSG_FATAL, "[export] Could not mmap file %s\n", s->filename); af_msg(AF_MSG_INFO, "[export] Memory mapped to file: %s (%p)\n", s->filename, s->mmap_area); // Initialize header *((int*)s->mmap_area) = af->data->nch; *((int*)s->mmap_area + 1) = s->sz * af->data->bps * af->data->nch; msync(s->mmap_area, mapsize, MS_ASYNC); // Use test_output to return FALSE if necessary return af_test_output(af, (af_data_t*)arg); } case AF_CONTROL_COMMAND_LINE:{ int i=0; char *str = arg; if (!str){ if(s->filename) free(s->filename); s->filename = get_path(SHARED_FILE); return AF_OK; } while((str[i]) && (str[i] != ':')) i++; if(s->filename) free(s->filename); s->filename = calloc(i + 1, 1); memcpy(s->filename, str, i); s->filename[i] = 0; sscanf(str + i + 1, "%d", &(s->sz)); return af->control(af, AF_CONTROL_EXPORT_SZ | AF_CONTROL_SET, &s->sz); } case AF_CONTROL_EXPORT_SZ | AF_CONTROL_SET: s->sz = * (int *) arg; if((s->sz <= 0) || (s->sz > 2048)) af_msg( AF_MSG_ERROR, "[export] Buffer size must be between" " 1 and 2048\n" ); return AF_OK; case AF_CONTROL_EXPORT_SZ | AF_CONTROL_GET: *(int*) arg = s->sz; return AF_OK; } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { switch(cmd){ case AF_CONTROL_REINIT:{ char buf1[256]; char buf2[256]; af_data_t *data = arg; // Make sure this filter isn't redundant if(af->data->format == data->format && af->data->bps == data->bps) return AF_DETACH; // Check for errors in configuraton if((AF_OK != check_bps(data->bps)) || (AF_OK != check_format(data->format)) || (AF_OK != check_bps(af->data->bps)) || (AF_OK != check_format(af->data->format))) return AF_ERROR; af_msg(AF_MSG_VERBOSE,"[format] Changing sample format from %s to %s\n", af_fmt2str(data->format,buf1,256), af_fmt2str(af->data->format,buf2,256)); af->data->rate = data->rate; af->data->nch = data->nch; af->mul.n = af->data->bps; af->mul.d = data->bps; af_frac_cancel(&af->mul); af->play = play; // set default // look whether only endianess differences are there if ((af->data->format & ~AF_FORMAT_END_MASK) == (data->format & ~AF_FORMAT_END_MASK)) { af_msg(AF_MSG_VERBOSE,"[format] Accelerated endianess conversion only\n"); af->play = play_swapendian; } if ((data->format == AF_FORMAT_FLOAT_NE) && (af->data->format == AF_FORMAT_S16_NE)) { af_msg(AF_MSG_VERBOSE,"[format] Accelerated %s to %s conversion\n", af_fmt2str(data->format,buf1,256), af_fmt2str(af->data->format,buf2,256)); af->play = play_float_s16; } if ((data->format == AF_FORMAT_S16_NE) && (af->data->format == AF_FORMAT_FLOAT_NE)) { af_msg(AF_MSG_VERBOSE,"[format] Accelerated %s to %s conversion\n", af_fmt2str(data->format,buf1,256), af_fmt2str(af->data->format,buf2,256)); af->play = play_s16_float; } return AF_OK; } case AF_CONTROL_COMMAND_LINE:{ int format = af_str2fmt_short(arg); if (format == -1) { af_msg(AF_MSG_ERROR, "[format] %s is not a valid format\n", (char *)arg); return AF_ERROR; } if(AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format)) return AF_ERROR; return AF_OK; } case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET:{ // Check for errors in configuraton if(AF_OK != check_format(*(int*)arg)) return AF_ERROR; af->data->format = *(int*)arg; af->data->bps = af_fmt2bits(af->data->format)/8; return AF_OK; } } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_equalizer_t* s = (af_equalizer_t*)af->setup; switch(cmd){ case AF_CONTROL_REINIT:{ int k =0, i =0; float F[KM] = CF; s->gain_factor=0.0; // Sanity check if(!arg) return AF_ERROR; af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch; af->data->format = AF_FORMAT_FLOAT_NE; af->data->bps = 4; // Calculate number of active filters s->K=KM; while(F[s->K-1] > (float)af->data->rate/2.2) s->K--; if(s->K != KM) af_msg(AF_MSG_INFO,"[equalizer] Limiting the number of filters to" " %i due to low sample rate.\n",s->K); // Generate filter taps for(k=0;k<s->K;k++) bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q); // Calculate how much this plugin adds to the overall time delay af->delay += 2000.0/((float)af->data->rate); // Calculate gain factor to prevent clipping at output for(k=0;k<AF_NCH;k++) { for(i=0;i<KM;i++) { if(s->gain_factor < s->g[k][i]) s->gain_factor=s->g[k][i]; } } s->gain_factor=log10(s->gain_factor + 1.0) * 20.0; if(s->gain_factor > 0.0) { s->gain_factor=0.1+(s->gain_factor/12.0); }else{ s->gain_factor=1; } return af_test_output(af,arg); } case AF_CONTROL_COMMAND_LINE:{ float g[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; int i,j; sscanf((char*)arg,"%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], &g[6], &g[7], &g[8] ,&g[9]); for(i=0;i<AF_NCH;i++){ for(j=0;j<KM;j++){ ((af_equalizer_t*)af->setup)->g[i][j] = pow(10.0,clamp(g[j],G_MIN,G_MAX)/20.0)-1.0; } } return AF_OK; } case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{ float* gain = ((af_control_ext_t*)arg)->arg; int ch = ((af_control_ext_t*)arg)->ch; int k; if(ch >= AF_NCH || ch < 0) return AF_ERROR; for(k = 0 ; k<KM ; k++) s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0; return AF_OK; } case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{ float* gain = ((af_control_ext_t*)arg)->arg; int ch = ((af_control_ext_t*)arg)->ch; int k; if(ch >= AF_NCH || ch < 0) return AF_ERROR; for(k = 0 ; k<KM ; k++) gain[k] = log10(s->g[ch][k]+1.0) * 20.0; return AF_OK; } } return AF_UNKNOWN; }