aflibaudiospectrum.cc

来自「一个共享源码的音频库2」· CC 代码 · 共 326 行

CC
326
字号
/* * Copyright: (C) 1999-2001 Bruce W. Forsberg * *   This library is free software; you can redistribute it and/or *   modify it under the terms of the GNU Lesser General Public *   License as published by the Free Software Foundation; either *   version 2.1 of the License, or any later version. * *   This library is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *   Lesser General Public License for more details. * *   You should have received a copy of the GNU Lesser General Public *   License along with this library; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA * *   Bruce Forsberg  forsberg@tns.net * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <iostream>#include <math.h>#include "aflibAudioSpectrum.h"#include "aflibData.h"/*! \brief Constuctor with an audio parent.     This will setup for 4 responses per second and 16 samples with 1 channel. No     callbacks are enabled.*/aflibAudioSpectrum::aflibAudioSpectrum(aflibAudio& audio) : aflibAudio(audio){   // Set reasonable defaults   _num_samples = 16;   _responses = 4;   _channels = 1;   _in_real = NULL;   _power_out = NULL;   _spec_out = NULL;   // Save the number of samples between responses   _samples_between_responses = audio.getOutputConfig().getSamplesPerSecond() / _responses;   _samples_counter = 0;   // Allocate in array   allocateMemory();   // Initially callbacks are disabled   _pm_func_ptr = NULL;   _spectrum_func_ptr = NULL;}/*! \brief Destructor.*/aflibAudioSpectrum::~aflibAudioSpectrum(){   delete [] _in_real;   delete [] _power_out;   delete [] _spec_out;}/*! \brief Sets parameters for the audio spectrum class.    This allows the user to set the number of samples to be returned    for the spectrum callback. It also determines the size of the    fft that is done for both the spectrum and power meter callbacks.    The number of samples must be a power of 2 upto 512. Another words,    valid values are: 2, 4, 8, 16, 32, 64, 128, 256, 512.    It also allows the user to set the number of times the callback    functions will get called a second. There are limits to how large    this value can be. It also depends on the sample rate of the audio    stream. Good values would be 10 or less. If an invalid number of    samples is set then FALSE will be returned.*/boolaflibAudioSpectrum::setParameters(   int num_samples,   int resp_per_sec,   int channels){   bool ret_status = TRUE;   _responses = resp_per_sec;   _channels = channels;   _samples_between_responses = getInputConfig().getSamplesPerSecond() / _responses;   _samples_counter = 0;   // Make sure a valid value was entered   switch (num_samples)   {      case 2:      case 4:      case 8:      case 16:      case 32:      case 64:      case 128:      case 256:      case 512:         _num_samples = num_samples;      break;      default:         ret_status = FALSE;      break;   }   // Reallocate memory since params have changed   allocateMemory();   return (ret_status);}/*! \brief Enables and disables power meter callback.    This function allows one to register a callback that will get    called whenever there is data processed showing what the power    is. It will be called based on the responses per second that was    set in the setParamters call. The user must register a function    that receives a double:    func(double val);    The value passed will be in decibels. In order to turn off the    callback pass NULL to this function.*/voidaflibAudioSpectrum::setPowerMeterCallback( powermeter_callback func_ptr){   _pm_func_ptr = func_ptr;	_pm = TRUE;}/*! \brief Enables and disables audio spectrum callback.    This function allows one to register a callback that will get    called whenever there is data processed showing what the audio    spectrum is. It will be called based on the responses per second    that was set in the setParamters call. The user must register a function    that receives an int and a double array:    func(int array_size, *double array);    The first value passed will be the size of the array passed. Users    should not read beyond this size. The array values passed will be    in decibels. When func is called users should copy the data if    they wish to save it as the memory will go out of scope when func    is exitted. In order to turn off the callback pass NULL to this function. */voidaflibAudioSpectrum::setAudioSpectrumCallback( spectrum_callback func_ptr){   _spectrum_func_ptr = func_ptr;	_spectrum = TRUE;}voidaflibAudioSpectrum::setPowerMeter(double* power_out){if (_pm_func_ptr)	_pm_func_ptr(power_out);}		voidaflibAudioSpectrum::setAudioSpectrum(int num_samples,double* spec_out){if (_spectrum_func_ptr)   _spectrum_func_ptr(num_samples, spec_out);}voidaflibAudioSpectrum::allocateMemory(){   delete [] _in_real;   delete [] _power_out;   delete [] _spec_out;   _in_real = new double[_num_samples * 2 * _channels];   _power_out = new double[_channels];   _spec_out = new double[_num_samples * _channels];}voidaflibAudioSpectrum::setInputConfig(const aflibConfig& cfg){   // This function overrides the virtual function in the aflibAudio base class.   // We do this so that we can read the audio configuration data. We then   // recalculate any data that is dependant on the audio configuration   _samples_between_responses = cfg.getSamplesPerSecond() / _responses;   _samples_counter = 0;   aflibAudio::setInputConfig(cfg);}aflibStatusaflibAudioSpectrum::compute_segment(   list<aflibData *>& data,   long long position) {   // This is the function that does all the work. It will gather audio data and then   // process it with the FFT when it is ready. data is passed in which contains   // a segment of the audio data. If multithreading is introduced then this function   // may need to be rewritten since data segments may come uot of sequence. Currently   // is function requires them to come in sequence since it uses data from more   // than one segment occasionally. We also in the future need to handle multi   // channel support.   double out_real[MAX_ARRAY_SIZE], out_imag[MAX_ARRAY_SIZE];   int  i, j, k;   double mag;   bool   data_ready = FALSE;   long length;   int  min_value, max_value;	double maxmin = 1.0;   (*data.begin())->getLength(length);   (*data.begin())->getMinMax(min_value, max_value);	maxmin = (double)max_value - (double)min_value;//	aflib_debug("min_value=%f\tmax_value=%f\tmaxmin=%f",min_value,max_value,maxmin);   // Increment our sample counter   _samples_counter += length;   // Check if it is time to gather samples   if (_samples_counter > _samples_between_responses)   {      int real_start, real_stop;      // Find where we left off in the array we pass to the FFT      real_start = _samples_counter - _samples_between_responses - length;      if (real_start < 0)         real_start = 0;      // Find where we should stop gathering samples in this array for the FFT for this segment      real_stop = _num_samples * 2;      if ((real_stop - real_start) > length)      {         real_stop = real_start + length;      }      else      {         data_ready = TRUE;      }      for (k = 0; k < _channels; k++)      {         for (i = real_start, j = 0; i < real_stop; i++, j++)         {            _in_real[i + (k * _num_samples * 2)] = (double)(*data.begin())->getSample(j, k);         }      }   }   // IF we have data then lets process it   if (data_ready)   {      for (k = 0; k < _channels; k++)      {         // IF one output is selected then process FFT         if (_pm || _spectrum)         {            _fft.fft_double(_num_samples * 2, FALSE, &_in_real[k * _num_samples * 2], NULL, out_real, out_imag);         }         // IF user wants power returned         if (_pm)         {            mag = out_real[0] * out_real[0] + out_imag[0] * out_imag[0];            _power_out[_channels-1] = sqrt(mag);            _power_out[_channels-1] =                20.0 * log10 (_power_out[_channels-1] / maxmin);         }         // IF user wants audio spectrum returned         if (_spectrum)         {            for (i = 1; i < _num_samples; i++)            {               mag = out_real[i] * out_real[i] + out_imag[i] * out_imag[i];               out_real[i] = sqrt(mag);               _spec_out[i + (k * _num_samples) - 1] =                   20.0 * log10 (out_real[i] / maxmin);//               fprintf(stderr,"spec_out=%f\tout_real=%f\tmaxmin=%f\n",_spec_out[i + (k * _num_samples) - 1],out_real[i],maxmin);            }         }      }      if (_pm)      {         setPowerMeter(_power_out);      }      if (_spectrum)      {         setAudioSpectrum(_num_samples, _spec_out);      }      if (_samples_between_responses != 0)      {         // reset the samples counter by looking for next segment         while (_samples_counter > _samples_between_responses)         {            _samples_counter -= _samples_between_responses;         }      }   }   return (AFLIB_SUCCESS);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?