tomwalters@275: // Copyright 2006-2010, Willem van Engen, Thomas Walters tomwalters@275: // tomwalters@275: // AIM-C: A C++ implementation of the Auditory Image Model tomwalters@275: // http://www.acousticscale.org/AIMC tomwalters@275: // tomwalters@275: // This program is free software: you can redistribute it and/or modify tomwalters@275: // it under the terms of the GNU General Public License as published by tomwalters@275: // the Free Software Foundation, either version 3 of the License, or tomwalters@275: // (at your option) any later version. tomwalters@275: // tomwalters@275: // This program is distributed in the hope that it will be useful, tomwalters@275: // but WITHOUT ANY WARRANTY; without even the implied warranty of tomwalters@275: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tomwalters@275: // GNU General Public License for more details. tomwalters@275: // tomwalters@275: // You should have received a copy of the GNU General Public License tomwalters@275: // along with this program. If not, see . tomwalters@275: tomwalters@275: /*! \file tomwalters@275: * \brief Audio file input tomwalters@275: * tomwalters@275: * \author Willem van Engen tomwalters@275: * \author Thomas Walters tomwalters@275: * \date created 2006/09/21 tomwalters@275: * \version \$Id$ tomwalters@275: */ tomwalters@275: tomwalters@275: #include tomwalters@275: tomwalters@275: #include "Modules/Input/ModuleFileInput.h" tomwalters@275: tomwalters@275: namespace aimc { tomwalters@275: ModuleFileInput::ModuleFileInput(Parameters *params) : Module(params) { tomwalters@278: module_description_ = "File input using libsndfile"; tomwalters@278: module_identifier_ = "file_input"; tomwalters@278: module_type_ = "input"; tomwalters@278: module_version_ = "$Id$"; tomwalters@278: tomwalters@279: file_handle_ = NULL; tomwalters@279: buffer_length_ = parameters_->DefaultInt("input.buffersize", 1024); tomwalters@275: tomwalters@275: file_position_samples_ = 0; tomwalters@275: file_loaded_ = false; tomwalters@275: audio_channels_ = 0; tomwalters@275: sample_rate_ = 0.0f; tomwalters@275: } tomwalters@275: tomwalters@275: ModuleFileInput::~ModuleFileInput() { tomwalters@292: if (file_handle_ != NULL) { tomwalters@279: sf_close(file_handle_); tomwalters@292: file_handle_ = NULL; tomwalters@292: } tomwalters@275: } tomwalters@275: tomwalters@275: void ModuleFileInput::ResetInternal() { tomwalters@275: output_.Initialize(audio_channels_, buffer_length_, sample_rate_); tomwalters@275: output_.set_start_time(0); tomwalters@275: } tomwalters@275: tomwalters@275: bool ModuleFileInput::LoadFile(const char* filename) { tomwalters@292: // If there's a file open. Close it. tomwalters@292: if (file_handle_ != NULL) { tomwalters@292: sf_close(file_handle_); tomwalters@292: file_handle_ = NULL; tomwalters@292: } tomwalters@279: // Open the file tomwalters@279: SF_INFO sfinfo; tomwalters@280: memset(reinterpret_cast(&sfinfo), 0, sizeof(SF_INFO)); tomwalters@292: tomwalters@279: file_handle_ = sf_open(filename, SFM_READ, &sfinfo); tomwalters@275: tomwalters@279: if (file_handle_ == NULL) { tomwalters@280: /*! \todo Also display error reason tomwalters@280: */ tomwalters@279: LOG_ERROR(_T("Couldn't read audio file '%s'"), filename); tomwalters@279: return false; tomwalters@279: } tomwalters@275: tomwalters@275: file_loaded_ = true; tomwalters@275: audio_channels_ = sfinfo.channels; tomwalters@275: sample_rate_ = sfinfo.samplerate; tomwalters@279: file_position_samples_ = 0; tomwalters@275: tomwalters@275: // A dummy signal bank to be passed to the Initialize() function. tomwalters@275: SignalBank s; tomwalters@275: s.Initialize(1, 1, 1); tomwalters@275: tomwalters@279: // Self-initialize by calling Module::Initialize() explicitly. tomwalters@279: // The Initialize() call in this subclass is overloaded to prevent it from tomwalters@279: // being called drectly. tomwalters@275: return Module::Initialize(s); tomwalters@275: } tomwalters@275: tomwalters@278: tomwalters@278: /* Do not call Initialize() on ModuleFileInput directly tomwalters@278: * instead call LoadFile() with a filename to load. tomwalters@278: * This will automatically initialize the module. tomwalters@278: */ tomwalters@275: bool ModuleFileInput::Initialize(const SignalBank& input) { tomwalters@275: LOG_ERROR(_T("Do not call Initialize() on ModuleFileInput directly " tomwalters@275: "instead call LoadFile() with a filename to load. " tomwalters@275: "This will automatically initialize the module.")); tomwalters@275: return false; tomwalters@275: } tomwalters@275: tomwalters@275: void ModuleFileInput::Process(const SignalBank& input) { tomwalters@275: LOG_ERROR(_T("Call Process() on ModuleFileInput instead of passing in " tomwalters@275: "a SignalBank")); tomwalters@275: } tomwalters@275: tomwalters@275: bool ModuleFileInput::InitializeInternal(const SignalBank& input) { tomwalters@278: if (!file_loaded_) { tomwalters@278: LOG_ERROR(_T("No file loaded in FileOutputHTK")); tomwalters@275: return false; tomwalters@278: } tomwalters@278: if (audio_channels_ < 1 || buffer_length_ < 1 || sample_rate_ < 0.0f) { tomwalters@278: LOG_ERROR(_T("audio_channels, buffer_length_ or sample_rate too small")); tomwalters@278: return false; tomwalters@278: } tomwalters@275: ResetInternal(); tomwalters@279: return true; tomwalters@275: } tomwalters@275: tomwalters@275: void ModuleFileInput::Process() { tomwalters@278: if (!file_loaded_) tomwalters@278: return; tomwalters@279: sf_count_t read; tomwalters@275: vector buffer; tomwalters@275: buffer.resize(buffer_length_ * audio_channels_); tomwalters@275: tomwalters@275: while (true) { tomwalters@279: // Read buffersize bytes into buffer tomwalters@279: read = sf_readf_float(file_handle_, &buffer[0], buffer_length_); tomwalters@275: tomwalters@275: // Place the contents of the buffer into the signal bank tomwalters@275: int counter = 0; tomwalters@275: for (int c = 0; c < audio_channels_; ++c) { tomwalters@275: for (int i = 0; i < read; ++i) { tomwalters@275: output_.set_sample(c, i, buffer[counter]); tomwalters@275: ++counter; tomwalters@275: } tomwalters@275: } tomwalters@275: tomwalters@279: // If the number of saples read is less than the buffer length, the end tomwalters@279: // of the file has been reached. tomwalters@279: if (read < buffer_length_) { tomwalters@279: // Zero samples at end tomwalters@279: for (int c = 0; c < audio_channels_; ++c) { tomwalters@275: for (int i = read; i < buffer_length_; ++i) { tomwalters@275: output_.set_sample(c, i, 0.0f); tomwalters@275: } tomwalters@275: } tomwalters@279: // When we're past the end of the buffer, stop looping. tomwalters@279: if (read == 0) tomwalters@275: break; tomwalters@279: } tomwalters@275: tomwalters@279: // Update time tomwalters@279: output_.set_start_time(file_position_samples_); tomwalters@279: file_position_samples_ += read; tomwalters@275: PushOutput(); tomwalters@275: } tomwalters@275: } tomwalters@275: } // namespace aimc