tomwalters@275
|
1 // Copyright 2006-2010, Willem van Engen, Thomas Walters
|
tomwalters@275
|
2 //
|
tomwalters@275
|
3 // AIM-C: A C++ implementation of the Auditory Image Model
|
tomwalters@275
|
4 // http://www.acousticscale.org/AIMC
|
tomwalters@275
|
5 //
|
tomwalters@275
|
6 // This program is free software: you can redistribute it and/or modify
|
tomwalters@275
|
7 // it under the terms of the GNU General Public License as published by
|
tomwalters@275
|
8 // the Free Software Foundation, either version 3 of the License, or
|
tomwalters@275
|
9 // (at your option) any later version.
|
tomwalters@275
|
10 //
|
tomwalters@275
|
11 // This program is distributed in the hope that it will be useful,
|
tomwalters@275
|
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
tomwalters@275
|
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
tomwalters@275
|
14 // GNU General Public License for more details.
|
tomwalters@275
|
15 //
|
tomwalters@275
|
16 // You should have received a copy of the GNU General Public License
|
tomwalters@275
|
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
|
tomwalters@275
|
18
|
tomwalters@275
|
19 /*! \file
|
tomwalters@275
|
20 * \brief Audio file input
|
tomwalters@275
|
21 *
|
tomwalters@275
|
22 * \author Willem van Engen <cnbh@willem.engen.nl>
|
tomwalters@275
|
23 * \author Thomas Walters <tom@acousticscale.org>
|
tomwalters@275
|
24 * \date created 2006/09/21
|
tomwalters@275
|
25 * \version \$Id$
|
tomwalters@275
|
26 */
|
tomwalters@275
|
27
|
tomwalters@275
|
28 #include <vector>
|
tomwalters@275
|
29
|
tomwalters@275
|
30 #include "Modules/Input/ModuleFileInput.h"
|
tomwalters@275
|
31
|
tomwalters@275
|
32 namespace aimc {
|
tomwalters@275
|
33 ModuleFileInput::ModuleFileInput(Parameters *params) : Module(params) {
|
tomwalters@278
|
34 module_description_ = "File input using libsndfile";
|
tomwalters@278
|
35 module_identifier_ = "file_input";
|
tomwalters@278
|
36 module_type_ = "input";
|
tomwalters@278
|
37 module_version_ = "$Id$";
|
tomwalters@278
|
38
|
tomwalters@279
|
39 file_handle_ = NULL;
|
tomwalters@279
|
40 buffer_length_ = parameters_->DefaultInt("input.buffersize", 1024);
|
tomwalters@275
|
41
|
tomwalters@275
|
42 file_position_samples_ = 0;
|
tomwalters@275
|
43 file_loaded_ = false;
|
tomwalters@275
|
44 audio_channels_ = 0;
|
tomwalters@275
|
45 sample_rate_ = 0.0f;
|
tomwalters@275
|
46 }
|
tomwalters@275
|
47
|
tomwalters@275
|
48 ModuleFileInput::~ModuleFileInput() {
|
tomwalters@275
|
49 if (file_handle_)
|
tomwalters@279
|
50 sf_close(file_handle_);
|
tomwalters@275
|
51 }
|
tomwalters@275
|
52
|
tomwalters@275
|
53 void ModuleFileInput::ResetInternal() {
|
tomwalters@275
|
54 output_.Initialize(audio_channels_, buffer_length_, sample_rate_);
|
tomwalters@275
|
55 output_.set_start_time(0);
|
tomwalters@275
|
56 }
|
tomwalters@275
|
57
|
tomwalters@275
|
58 bool ModuleFileInput::LoadFile(const char* filename) {
|
tomwalters@279
|
59 // Open the file
|
tomwalters@279
|
60 SF_INFO sfinfo;
|
tomwalters@280
|
61 memset(reinterpret_cast<void*>(&sfinfo), 0, sizeof(SF_INFO));
|
tomwalters@279
|
62 file_handle_ = sf_open(filename, SFM_READ, &sfinfo);
|
tomwalters@275
|
63
|
tomwalters@279
|
64 if (file_handle_ == NULL) {
|
tomwalters@280
|
65 /*! \todo Also display error reason
|
tomwalters@280
|
66 */
|
tomwalters@279
|
67 LOG_ERROR(_T("Couldn't read audio file '%s'"), filename);
|
tomwalters@279
|
68 return false;
|
tomwalters@279
|
69 }
|
tomwalters@275
|
70
|
tomwalters@275
|
71 file_loaded_ = true;
|
tomwalters@275
|
72 audio_channels_ = sfinfo.channels;
|
tomwalters@275
|
73 sample_rate_ = sfinfo.samplerate;
|
tomwalters@279
|
74 file_position_samples_ = 0;
|
tomwalters@275
|
75
|
tomwalters@275
|
76 // A dummy signal bank to be passed to the Initialize() function.
|
tomwalters@275
|
77 SignalBank s;
|
tomwalters@275
|
78 s.Initialize(1, 1, 1);
|
tomwalters@275
|
79
|
tomwalters@279
|
80 // Self-initialize by calling Module::Initialize() explicitly.
|
tomwalters@279
|
81 // The Initialize() call in this subclass is overloaded to prevent it from
|
tomwalters@279
|
82 // being called drectly.
|
tomwalters@275
|
83 return Module::Initialize(s);
|
tomwalters@275
|
84 }
|
tomwalters@275
|
85
|
tomwalters@278
|
86
|
tomwalters@278
|
87 /* Do not call Initialize() on ModuleFileInput directly
|
tomwalters@278
|
88 * instead call LoadFile() with a filename to load.
|
tomwalters@278
|
89 * This will automatically initialize the module.
|
tomwalters@278
|
90 */
|
tomwalters@275
|
91 bool ModuleFileInput::Initialize(const SignalBank& input) {
|
tomwalters@275
|
92 LOG_ERROR(_T("Do not call Initialize() on ModuleFileInput directly "
|
tomwalters@275
|
93 "instead call LoadFile() with a filename to load. "
|
tomwalters@275
|
94 "This will automatically initialize the module."));
|
tomwalters@275
|
95 return false;
|
tomwalters@275
|
96 }
|
tomwalters@275
|
97
|
tomwalters@275
|
98 void ModuleFileInput::Process(const SignalBank& input) {
|
tomwalters@275
|
99 LOG_ERROR(_T("Call Process() on ModuleFileInput instead of passing in "
|
tomwalters@275
|
100 "a SignalBank"));
|
tomwalters@275
|
101 }
|
tomwalters@275
|
102
|
tomwalters@275
|
103 bool ModuleFileInput::InitializeInternal(const SignalBank& input) {
|
tomwalters@278
|
104 if (!file_loaded_) {
|
tomwalters@278
|
105 LOG_ERROR(_T("No file loaded in FileOutputHTK"));
|
tomwalters@275
|
106 return false;
|
tomwalters@278
|
107 }
|
tomwalters@278
|
108 if (audio_channels_ < 1 || buffer_length_ < 1 || sample_rate_ < 0.0f) {
|
tomwalters@278
|
109 LOG_ERROR(_T("audio_channels, buffer_length_ or sample_rate too small"));
|
tomwalters@278
|
110 return false;
|
tomwalters@278
|
111 }
|
tomwalters@275
|
112 ResetInternal();
|
tomwalters@279
|
113 return true;
|
tomwalters@275
|
114 }
|
tomwalters@275
|
115
|
tomwalters@275
|
116 void ModuleFileInput::Process() {
|
tomwalters@278
|
117 if (!file_loaded_)
|
tomwalters@278
|
118 return;
|
tomwalters@279
|
119 sf_count_t read;
|
tomwalters@275
|
120 vector<float> buffer;
|
tomwalters@275
|
121 buffer.resize(buffer_length_ * audio_channels_);
|
tomwalters@275
|
122
|
tomwalters@275
|
123 while (true) {
|
tomwalters@279
|
124 // Read buffersize bytes into buffer
|
tomwalters@279
|
125 read = sf_readf_float(file_handle_, &buffer[0], buffer_length_);
|
tomwalters@275
|
126
|
tomwalters@275
|
127 // Place the contents of the buffer into the signal bank
|
tomwalters@275
|
128 int counter = 0;
|
tomwalters@275
|
129 for (int c = 0; c < audio_channels_; ++c) {
|
tomwalters@275
|
130 for (int i = 0; i < read; ++i) {
|
tomwalters@275
|
131 output_.set_sample(c, i, buffer[counter]);
|
tomwalters@275
|
132 ++counter;
|
tomwalters@275
|
133 }
|
tomwalters@275
|
134 }
|
tomwalters@275
|
135
|
tomwalters@279
|
136 // If the number of saples read is less than the buffer length, the end
|
tomwalters@279
|
137 // of the file has been reached.
|
tomwalters@279
|
138 if (read < buffer_length_) {
|
tomwalters@279
|
139 // Zero samples at end
|
tomwalters@279
|
140 for (int c = 0; c < audio_channels_; ++c) {
|
tomwalters@275
|
141 for (int i = read; i < buffer_length_; ++i) {
|
tomwalters@275
|
142 output_.set_sample(c, i, 0.0f);
|
tomwalters@275
|
143 }
|
tomwalters@275
|
144 }
|
tomwalters@279
|
145 // When we're past the end of the buffer, stop looping.
|
tomwalters@279
|
146 if (read == 0)
|
tomwalters@275
|
147 break;
|
tomwalters@279
|
148 }
|
tomwalters@275
|
149
|
tomwalters@279
|
150 // Update time
|
tomwalters@279
|
151 output_.set_start_time(file_position_samples_);
|
tomwalters@279
|
152 file_position_samples_ += read;
|
tomwalters@275
|
153 PushOutput();
|
tomwalters@275
|
154 }
|
tomwalters@275
|
155 }
|
tomwalters@275
|
156 } // namespace aimc
|