/**************************************************************************** * apps/audioutils/fmsynth/fmsynth_eg.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define CONVERT_INITVAL(lv) (int)((lv) * FMSYNTH_MAX_EGLEVEL) /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * name: set_egparams ****************************************************************************/ static int set_egparams(int fs, FAR fmsynth_egparam_t *param, FAR struct fmsynth_eglevel_s *target_level, FAR struct fmsynth_eglevel_s *last_level) { param->initval = CONVERT_INITVAL(last_level->level); param->period = fs * target_level->period_ms / 1000; param->diff2next = CONVERT_INITVAL(target_level->level) - CONVERT_INITVAL(last_level->level); if (param->initval < -FMSYNTH_MAX_EGLEVEL || param->initval > FMSYNTH_MAX_EGLEVEL || param->period < 0) { return -1; } return 0; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * name: create_fmsyntheg ****************************************************************************/ FAR fmsynth_eg_t *create_fmsyntheg(FAR fmsynth_eg_t *eg) { int i; if (eg) { eg->state = EGSTATE_RELEASED; eg->state_counter = 0; for (i = 0; i < EGSTATE_MAX; i++) { eg->state_params[i].initval = 0; eg->state_params[i].period = 0; } eg->state_params[EGSTATE_RELEASED].initval = FMSYNTH_MAX_EGLEVEL; } return eg; } /**************************************************************************** * name: fmsyntheg_create ****************************************************************************/ FAR fmsynth_eg_t *fmsyntheg_create(void) { FAR fmsynth_eg_t *ret = (FAR fmsynth_eg_t *)malloc(sizeof(fmsynth_eg_t)); return create_fmsyntheg(ret); } /**************************************************************************** * name: fmsyntheg_delete ****************************************************************************/ void fmsyntheg_delete(FAR fmsynth_eg_t *eg) { if (eg != NULL) { free(eg); } } /**************************************************************************** * name: fmsyntheg_set_param ****************************************************************************/ int fmsyntheg_set_param(FAR fmsynth_eg_t *eg, int fs, FAR fmsynth_eglevels_t *levels) { int errcnt = 0; if (fs <= 0) { return ERROR; } errcnt += set_egparams(fs, &eg->state_params[EGSTATE_ATTACK], &levels->attack, &levels->release); errcnt += set_egparams(fs, &eg->state_params[EGSTATE_DECAYBREAK], &levels->decaybrk, &levels->attack); errcnt += set_egparams(fs, &eg->state_params[EGSTATE_DECAY], &levels->decay, &levels->decaybrk); errcnt += set_egparams(fs, &eg->state_params[EGSTATE_SUSTAIN], &levels->sustain, &levels->decay); errcnt += set_egparams(fs, &eg->state_params[EGSTATE_RELEASE], &levels->release, &levels->sustain); eg->state_params[EGSTATE_RELEASED].initval = CONVERT_INITVAL(levels->release.level); return errcnt ? ERROR : OK; } /**************************************************************************** * name: fmsyntheg_start ****************************************************************************/ void fmsyntheg_start(FAR fmsynth_eg_t *eg) { eg->state = EGSTATE_ATTACK; eg->state_counter = 0; } /**************************************************************************** * name: fmsyntheg_stop ****************************************************************************/ void fmsyntheg_stop(FAR fmsynth_eg_t *eg) { eg->state = EGSTATE_RELEASED; eg->state_counter = 0; } /**************************************************************************** * name: fmsyntheg_operate ****************************************************************************/ int fmsyntheg_operate(FAR fmsynth_eg_t *eg) { int val; FAR fmsynth_egparam_t *param = &eg->state_params[eg->state]; val = param->initval; if (eg->state != EGSTATE_RELEASED) { if (eg->state_counter >= eg->state_params[eg->state].period) { /* Reset the counter */ eg->state_counter = 0; /* Search next available state */ do { eg->state++; } while (eg->state < EGSTATE_RELEASED && eg->state_params[eg->state].period == 0); val = eg->state_params[eg->state].initval; } else { val = val + param->diff2next * eg->state_counter / param->period; eg->state_counter++; } } return val; }