aflibaudio.cc
来自「一个共享源码的音频库2」· CC 代码 · 共 778 行 · 第 1/2 页
CC
778 行
/* * 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 <stdlib.h>#include <iostream>using std::cerr;using std::endl;#include "aflibAudio.h"#include "aflibAudioMixer.h"#include "aflibData.h"#include "aflibDebug.h"#include "aflibAudioSampleRateCvt.h"int aflibAudio::_level = 0;/*! \brief Constructor. This constructor is for derived classes that have no parent audio object. */aflibAudio::aflibAudio() : aflibChain(), aflibMemCache(){ // This node is enabled by default _enable = TRUE; // All conversions enabled by default _enable_data_size = TRUE; _enable_endian = TRUE; _enable_channels = TRUE; _enable_sample_rate = TRUE; _cvt = NULL; _mix = NULL;}/*! \brief Constructor. This constructor is for derived classes that have a parent audio object. */aflibAudio::aflibAudio( aflibAudio& audio) : aflibChain(audio), aflibMemCache(){ // This node is enabled by default _enable = TRUE; // All conversions enabled by default _enable_data_size = TRUE; _enable_endian = TRUE; _enable_channels = TRUE; _enable_sample_rate = TRUE; _cvt = NULL; _mix = NULL; setInputConfig(audio.getInputConfig());}/*! \brief Destructor.*/aflibAudio::~aflibAudio(){ delete _cvt; delete _mix;}/*! \brief Enables or disables an object in a chain. This allows this node to be enabled or disabled. This assists in removing a node from a chain without having to destruct it. This is useful to enable an application to toggle a filter in and out for example.*/voidaflibAudio::enable(bool enable){ // IF Changing state of chain then reprocess chain if (enable != _enable) setNodeProcessed(FALSE); _enable = enable; }/*! \brief Gets current state of object. This allows one to determine if an object is Enabled or Disabled. TRUE means that the object is currently enabled.*/boolaflibAudio::getEnable() const{ return(_enable);}/*! \brief Enables or disables data size conversion. This allows the automatic data size conversion feature to be enabled or disabled. This is already enabled by default. If one does not want a node to perform a data size conversion then this can be set on a node to disable it.*/voidaflibAudio::enableDataSizeConversion(bool enable){ _enable_data_size = enable;}/*! \brief Enables or disables endian conversion. This allows the endian data conversion feature to be enabled or disabled. This is already enabled by default. If one does not want a node to perform an endian conversion then this can be set on a node to disable it.*/voidaflibAudio::enableEndianConversion(bool enable){ _enable_endian = enable;}/*! \brief Enables or disables sample rate conversion. This allows the automatic sample rate conversion feature to be enabled or disabled. This is already enabled by default. If one does not want a node to perform a sample rate conversion then this can be set on a node to disable it.*/voidaflibAudio::enableSampleRateConversion(bool enable){ _enable_sample_rate = enable;}/*! \brief Enables or disables number of channels conversion. This allows the automatic channel conversion feature to be enabled or disabled. This is already enabled by default. If one does not want a node to perform a mixing operation to convert the number of channels then this can be set on a node to disable it.*/voidaflibAudio::enableChannelsConversion(bool enable){ _enable_channels = enable;}/*! \brief Sets the input audio data configuration of an object. This is a virtual function that derived classes can override if needed. It allows the caller to set the configuration of the audio data of an object. By default it saves the output audio configuration to be the same as the input data configuration that is passed in. This should be sufficient for most derived classes. For those classes that will have a change from the output to input config mapping then this function should be overriden and the output config processed and saved.*/voidaflibAudio::setInputConfig(const aflibConfig& cfg){ _cfg_input = cfg; // As a default create a 1-1 config mapping between input and output setOutputConfig(_cfg_input);}/*! \brief Returns the input audio data configuration of an object.*/ const aflibConfig&aflibAudio::getInputConfig() const{ return (_cfg_input);}/*! \brief Sets the output audio data configuration of an object. This is a virtual function that derived classes can override if needed. Most derived classes will not need to override this function but can simply call it to store the output audio configuration. It is virtual so that it can be overriden by the aflibAudioFile class which needs to implement its own.*/voidaflibAudio::setOutputConfig(const aflibConfig& cfg){ _cfg_output = cfg;}/*! \brief Returns the output audio data configuration of an object.*/ const aflibConfig&aflibAudio::getOutputConfig() const{ return (_cfg_output);}/*! \brief Main processing function for pulling data thru an audio chain. This is the main processing function for pulling data thru an audio chain. It can be called from any aflibAudio derived object. Users should call the process function at the end of a chain. This function will then call each process function in an audio chain until the start of the chain is reached. When the start of the chain is reached then an aflibData object of the proper size will be allocated and each aflibAudio derived objects compute_segment function will be called to process the data until the end of the chain is reached. This implementation will handle multiple parents automatically. It will request data from the same position and size from each parent of an object. It data of a different size or position is needed from each parent then this will need to be overriden in the derived class. This is not recommended. The first parameter will return a status to the caller. If everything worked OK then AFLIB_SUCCESS will be returned. The second is a position parameter. This indicates at which position in an audio source to read data from. This is a suggestion. It will be ignored if reading from an audio device or from an audio format that does not support random access, like mp3. The third parameter is the number of samples to pull thru the chain. If 0 is passed then the library will pick the size. This is a suggestion. It will return the actual number of samples used when pulling data thru the chain. If the caller passes FALSE to free_memory then the pointer to the aflibData class containing the data will be returned. It is then the responsibility of the calling app to free this memory using delete. If no parameter is passed then it will not be returned by default. Instead NULL will be returned.*/ aflibData *aflibAudio::process( aflibStatus& ret_status, long long position, int& num_samples, bool free_memory) { int list_size = 0; aflibData * data = NULL; long length; long long orig_position = position; int orig_num_samples = num_samples; aflibStatus save_status; list<aflibData *> d_list; list<aflibData *>::iterator it_data ; map<int, aflibAudio *, less<int> > audio_list; map<int, aflibAudio *, less<int> >::iterator it; // Set default return status and level indicator ret_status = AFLIB_SUCCESS; incrementLevel(); // Check to see if chain has been preprocessed if at start of chain examineChain(); audio_list = this->getParents(); list_size = audio_list.size(); if (list_size > 1) { // disable caching if more than one parent setCacheEnable(FALSE); } // IF no parents then cache are input. if (list_size == 0) { // IF node is not enabled then skip processing if (_enable == TRUE) { if (num_samples == 0) num_samples = 4096; data = new aflibData(num_samples); // Lets look in the cache and see if we have data if (getCacheEnable() == TRUE) lookupData(position, num_samples); d_list.push_back(data); // IF not all the data is in the cache if (num_samples != 0) { ret_status = compute_segment(d_list, position); } // ELSE all data is in the cache else { // Since we will get all data from the cache we need to get the config // data from the object. data->setConfig(getOutputConfig()); } if (getCacheEnable() == TRUE) { // Cache audio data and Fill in data object with data from cache fillDataFromCache(*data, position, num_samples, orig_position, orig_num_samples); } } } // ELSE call parent and let it process it first then process result else { // Lets look in the cache and see if we have data if (getCacheEnable() == TRUE) lookupData(position, num_samples); // IF all data is in cache then we are done if (num_samples != 0) { // set initial status to success save_status = AFLIB_SUCCESS; for (it = audio_list.begin(); it != audio_list.end(); it++) { d_list.push_back(((aflibAudio*)( (*it).second))->process( ret_status, position, num_samples, FALSE)); // IF there is a error returned then set overall error state to error if (save_status == AFLIB_SUCCESS) save_status = ret_status; } ret_status = save_status; } if (ret_status == AFLIB_SUCCESS) { // ptr can be NULL if parent was not enabled if ((*d_list.begin()) == NULL) { d_list.erase(d_list.begin()); if (num_samples == 0) d_list.push_back(new aflibData(4096)); else d_list.push_back(new aflibData(num_samples)); } // IF data was entirely in cache then data list will be empty // TBD what about of num_samples specified was 0. if (d_list.size() == 0) d_list.push_back(new aflibData(getInputConfig(), orig_num_samples)); if (_enable == TRUE) { for (it_data = d_list.begin(); it_data != d_list.end(); it_data++) { // Convert data to correct format convertData(**it_data); } if (getCacheEnable() == TRUE) { // Cache audio data and Fill in data object with data from cache fillDataFromCache(**(d_list.begin()), position, num_samples, orig_position, orig_num_samples); } ret_status = compute_segment(d_list, position); } } } // Set num_samples with correct value
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?