// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_gate_t* s = (af_gate_t*)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 = ((af_data_t*)arg)->nch; af->data->format = AF_FORMAT_FLOAT_NE; af->data->bps = 4; // Time constant set to 0.1s // s->alpha = (1.0/0.2)/(2.0*M_PI*(float)((af_data_t*)arg)->rate); return af_test_output(af,(af_data_t*)arg); case AF_CONTROL_COMMAND_LINE:{ /* float v=-10.0; */ /* float vol[AF_NCH]; */ /* float s=0.0; */ /* float clipp[AF_NCH]; */ /* int i; */ /* sscanf((char*)arg,"%f:%f", &v, &s); */ /* for(i=0;i<AF_NCH;i++){ */ /* vol[i]=v; */ /* clipp[i]=s; */ /* } */ /* if(AF_OK != control(af,AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET, clipp)) */ /* return AF_ERROR; */ /* return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol); */ } case AF_CONTROL_GATE_ON_OFF | AF_CONTROL_SET: memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int)); return AF_OK; case AF_CONTROL_GATE_ON_OFF | AF_CONTROL_GET: memcpy((int*)arg,s->enable,AF_NCH*sizeof(int)); return AF_OK; case AF_CONTROL_GATE_THRESH | AF_CONTROL_SET: return af_from_dB(AF_NCH,(float*)arg,s->tresh,20.0,-60.0,-1.0); case AF_CONTROL_GATE_THRESH | AF_CONTROL_GET: return af_to_dB(AF_NCH,s->tresh,(float*)arg,10.0); case AF_CONTROL_GATE_ATTACK | AF_CONTROL_SET: return af_from_ms(AF_NCH,(float*)arg,s->attack,af->data->rate,500.0,0.1); case AF_CONTROL_GATE_ATTACK | AF_CONTROL_GET: return af_to_ms(AF_NCH,s->attack,(float*)arg,af->data->rate); case AF_CONTROL_GATE_RELEASE | AF_CONTROL_SET: return af_from_ms(AF_NCH,(float*)arg,s->release,af->data->rate,3000.0,10.0); case AF_CONTROL_GATE_RELEASE | AF_CONTROL_GET: return af_to_ms(AF_NCH,s->release,(float*)arg,af->data->rate); case AF_CONTROL_GATE_RANGE | AF_CONTROL_SET: return af_from_dB(AF_NCH,(float*)arg,s->range,20.0,100.0,0.0); case AF_CONTROL_GATE_RANGE | AF_CONTROL_GET: return af_to_dB(AF_NCH,s->range,(float*)arg,10.0); } return AF_UNKNOWN; }
void mixer_setvolume(mixer_t *mixer, float l, float r) { ao_control_vol_t vol; vol.right=r; vol.left=l; if(mixer->audio_out){ if(soft_vol || CONTROL_OK != mixer->audio_out->control(AOCONTROL_SET_VOLUME,&vol)) { if (!mixer->afilter) return; else { // af_volume uses values in dB float db_vals[AF_NCH]; int i; db_vals[0] = (l / 100.0) * (soft_vol_max / 100.0); db_vals[1] = (r / 100.0) * (soft_vol_max / 100.0); for (i = 2; i < AF_NCH; i++) { db_vals[i] = ((l + r) / 100.0) * (soft_vol_max / 100.0) / 2.0; } af_to_dB (AF_NCH, db_vals, db_vals, 20.0); if (!af_control_any_rev(mixer->afilter, AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, db_vals)) { mp_msg(MSGT_GLOBAL, MSGL_INFO, MSGTR_InsertingAfVolume); if (af_add(mixer->afilter, "volume")) { if (!af_control_any_rev(mixer->afilter, AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, db_vals)) { mp_msg(MSGT_GLOBAL, MSGL_ERR, MSGTR_NoVolume); return; } } } } } } mixer->muted=0; }
static void setvolume_internal(mixer_t *mixer, float l, float r) { struct ao_control_vol vol = {.left = l, .right = r}; if (!mixer->softvol) { // relies on the driver data being permanent (so ptr stays valid) mixer->restore_volume = mixer->ao->no_persistent_volume ? mixer->ao->driver->info->short_name : NULL; if (ao_control(mixer->ao, AOCONTROL_SET_VOLUME, &vol) != CONTROL_OK) mp_tmsg(MSGT_GLOBAL, MSGL_ERR, "[Mixer] Failed to change audio output volume.\n"); return; } mixer->restore_volume = "softvol"; if (!mixer->afilter) return; // af_volume uses values in dB float db_vals[AF_NCH]; int i; db_vals[0] = (l / 100.0) * (mixer->softvol_max / 100.0); db_vals[1] = (r / 100.0) * (mixer->softvol_max / 100.0); for (i = 2; i < AF_NCH; i++) db_vals[i] = ((l + r) / 100.0) * (mixer->softvol_max / 100.0) / 2.0; af_to_dB(AF_NCH, db_vals, db_vals, 20.0); if (!af_control_any_rev(mixer->afilter, AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, db_vals)) { mp_tmsg(MSGT_GLOBAL, mixer->softvol ? MSGL_V : MSGL_WARN, "[Mixer] No hardware mixing, inserting volume filter.\n"); if (!(af_add(mixer->afilter, "volume") && af_control_any_rev(mixer->afilter, AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, db_vals))) mp_tmsg(MSGT_GLOBAL, MSGL_ERR, "[Mixer] No volume control available.\n"); } }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_volume_t* s = (af_volume_t*)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 = ((af_data_t*)arg)->nch; if(s->fast && (((af_data_t*)arg)->format != (AF_FORMAT_FLOAT_NE))){ af->data->format = AF_FORMAT_S16_NE; af->data->bps = 2; } else{ // Cutoff set to 10Hz for forgetting factor float x = 2.0*M_PI*15.0/(float)af->data->rate; float t = 2.0-cos(x); s->time = 1.0 - (t - sqrt(t*t - 1)); mp_msg(MSGT_AFILTER, MSGL_DBG2, "[volume] Forgetting factor = %0.5f\n",s->time); af->data->format = AF_FORMAT_FLOAT_NE; af->data->bps = 4; } return af_test_output(af,(af_data_t*)arg); case AF_CONTROL_COMMAND_LINE:{ float v=0.0; float vol[AF_NCH]; int i; sscanf((char*)arg,"%f:%i", &v, &s->soft); for(i=0;i<AF_NCH;i++) vol[i]=v; return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol); } case AF_CONTROL_POST_CREATE: s->fast = ((((af_cfg_t*)arg)->force & AF_INIT_FORMAT_MASK) == AF_INIT_FLOAT) ? 0 : 1; return AF_OK; case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_SET: memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int)); return AF_OK; case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_GET: memcpy((int*)arg,s->enable,AF_NCH*sizeof(int)); return AF_OK; case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET: s->soft = *(int*)arg; return AF_OK; case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_GET: *(int*)arg = s->soft; return AF_OK; case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET: return af_from_dB(AF_NCH,(float*)arg,s->level,20.0,-200.0,60.0); case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET: return af_to_dB(AF_NCH,s->level,(float*)arg,20.0); case AF_CONTROL_VOLUME_PROBE | AF_CONTROL_GET: return af_to_dB(AF_NCH,s->pow,(float*)arg,10.0); case AF_CONTROL_VOLUME_PROBE_MAX | AF_CONTROL_GET: return af_to_dB(AF_NCH,s->max,(float*)arg,10.0); case AF_CONTROL_PRE_DESTROY:{ float m = 0.0; int i; if(!s->fast){ for(i=0;i<AF_NCH;i++) m=max(m,s->max[i]); af_to_dB(1, &m, &m, 10.0); mp_msg(MSGT_AFILTER, MSGL_INFO, "[volume] The maximum volume was %0.2fdB \n", m); } return AF_OK; } } return AF_UNKNOWN; }