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@318
|
6 // Licensed under the Apache License, Version 2.0 (the "License");
|
tomwalters@318
|
7 // you may not use this file except in compliance with the License.
|
tomwalters@318
|
8 // You may obtain a copy of the License at
|
tomwalters@275
|
9 //
|
tomwalters@318
|
10 // http://www.apache.org/licenses/LICENSE-2.0
|
tomwalters@275
|
11 //
|
tomwalters@318
|
12 // Unless required by applicable law or agreed to in writing, software
|
tomwalters@318
|
13 // distributed under the License is distributed on an "AS IS" BASIS,
|
tomwalters@318
|
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
tomwalters@318
|
15 // See the License for the specific language governing permissions and
|
tomwalters@318
|
16 // limitations under the License.
|
tomwalters@275
|
17
|
tomwalters@275
|
18 /*! \file
|
tomwalters@275
|
19 * \brief Audio file input
|
tomwalters@275
|
20 *
|
tomwalters@275
|
21 * \author Willem van Engen <cnbh@willem.engen.nl>
|
tomwalters@275
|
22 * \author Thomas Walters <tom@acousticscale.org>
|
tomwalters@275
|
23 * \date created 2006/09/21
|
tomwalters@275
|
24 * \version \$Id$
|
tomwalters@275
|
25 */
|
tomwalters@275
|
26
|
tomwalters@275
|
27 #include <vector>
|
tomwalters@275
|
28
|
tomwalters@275
|
29 #include "Modules/Input/ModuleFileInput.h"
|
tomwalters@275
|
30
|
tomwalters@275
|
31 namespace aimc {
|
tomwalters@275
|
32 ModuleFileInput::ModuleFileInput(Parameters *params) : Module(params) {
|
tomwalters@278
|
33 module_description_ = "File input using libsndfile";
|
tomwalters@278
|
34 module_identifier_ = "file_input";
|
tomwalters@278
|
35 module_type_ = "input";
|
tomwalters@278
|
36 module_version_ = "$Id$";
|
tomwalters@278
|
37
|
tomwalters@279
|
38 file_handle_ = NULL;
|
tomwalters@279
|
39 buffer_length_ = parameters_->DefaultInt("input.buffersize", 1024);
|
tomwalters@275
|
40
|
tomwalters@275
|
41 file_position_samples_ = 0;
|
tomwalters@275
|
42 file_loaded_ = false;
|
tomwalters@275
|
43 audio_channels_ = 0;
|
tomwalters@275
|
44 sample_rate_ = 0.0f;
|
tomwalters@275
|
45 }
|
tomwalters@275
|
46
|
tomwalters@275
|
47 ModuleFileInput::~ModuleFileInput() {
|
tomwalters@292
|
48 if (file_handle_ != NULL) {
|
tomwalters@279
|
49 sf_close(file_handle_);
|
tomwalters@292
|
50 file_handle_ = NULL;
|
tomwalters@292
|
51 }
|
tomwalters@275
|
52 }
|
tomwalters@275
|
53
|
tomwalters@275
|
54 void ModuleFileInput::ResetInternal() {
|
tomwalters@275
|
55 output_.Initialize(audio_channels_, buffer_length_, sample_rate_);
|
tomwalters@275
|
56 output_.set_start_time(0);
|
tomwalters@275
|
57 }
|
tomwalters@275
|
58
|
tomwalters@275
|
59 bool ModuleFileInput::LoadFile(const char* filename) {
|
tomwalters@292
|
60 // If there's a file open. Close it.
|
tomwalters@292
|
61 if (file_handle_ != NULL) {
|
tomwalters@292
|
62 sf_close(file_handle_);
|
tomwalters@292
|
63 file_handle_ = NULL;
|
tomwalters@292
|
64 }
|
tomwalters@279
|
65 // Open the file
|
tomwalters@279
|
66 SF_INFO sfinfo;
|
tomwalters@280
|
67 memset(reinterpret_cast<void*>(&sfinfo), 0, sizeof(SF_INFO));
|
tomwalters@292
|
68
|
tomwalters@279
|
69 file_handle_ = sf_open(filename, SFM_READ, &sfinfo);
|
tomwalters@275
|
70
|
tomwalters@279
|
71 if (file_handle_ == NULL) {
|
tomwalters@280
|
72 /*! \todo Also display error reason
|
tomwalters@280
|
73 */
|
tomwalters@279
|
74 LOG_ERROR(_T("Couldn't read audio file '%s'"), filename);
|
tomwalters@279
|
75 return false;
|
tomwalters@279
|
76 }
|
tomwalters@275
|
77
|
tomwalters@275
|
78 file_loaded_ = true;
|
tomwalters@275
|
79 audio_channels_ = sfinfo.channels;
|
tomwalters@275
|
80 sample_rate_ = sfinfo.samplerate;
|
tomwalters@279
|
81 file_position_samples_ = 0;
|
tomwalters@275
|
82
|
tomwalters@275
|
83 // A dummy signal bank to be passed to the Initialize() function.
|
tomwalters@275
|
84 SignalBank s;
|
tomwalters@275
|
85 s.Initialize(1, 1, 1);
|
tomwalters@275
|
86
|
tomwalters@279
|
87 // Self-initialize by calling Module::Initialize() explicitly.
|
tomwalters@279
|
88 // The Initialize() call in this subclass is overloaded to prevent it from
|
tomwalters@279
|
89 // being called drectly.
|
tomwalters@275
|
90 return Module::Initialize(s);
|
tomwalters@275
|
91 }
|
tomwalters@275
|
92
|
tomwalters@278
|
93
|
tomwalters@278
|
94 /* Do not call Initialize() on ModuleFileInput directly
|
tomwalters@278
|
95 * instead call LoadFile() with a filename to load.
|
tomwalters@278
|
96 * This will automatically initialize the module.
|
tomwalters@278
|
97 */
|
tomwalters@275
|
98 bool ModuleFileInput::Initialize(const SignalBank& input) {
|
tomwalters@275
|
99 LOG_ERROR(_T("Do not call Initialize() on ModuleFileInput directly "
|
tomwalters@275
|
100 "instead call LoadFile() with a filename to load. "
|
tomwalters@275
|
101 "This will automatically initialize the module."));
|
tomwalters@275
|
102 return false;
|
tomwalters@275
|
103 }
|
tomwalters@275
|
104
|
tomwalters@275
|
105 void ModuleFileInput::Process(const SignalBank& input) {
|
tomwalters@275
|
106 LOG_ERROR(_T("Call Process() on ModuleFileInput instead of passing in "
|
tomwalters@275
|
107 "a SignalBank"));
|
tomwalters@275
|
108 }
|
tomwalters@275
|
109
|
tomwalters@275
|
110 bool ModuleFileInput::InitializeInternal(const SignalBank& input) {
|
tomwalters@278
|
111 if (!file_loaded_) {
|
tomwalters@278
|
112 LOG_ERROR(_T("No file loaded in FileOutputHTK"));
|
tomwalters@275
|
113 return false;
|
tomwalters@278
|
114 }
|
tomwalters@278
|
115 if (audio_channels_ < 1 || buffer_length_ < 1 || sample_rate_ < 0.0f) {
|
tomwalters@278
|
116 LOG_ERROR(_T("audio_channels, buffer_length_ or sample_rate too small"));
|
tomwalters@278
|
117 return false;
|
tomwalters@278
|
118 }
|
tomwalters@275
|
119 ResetInternal();
|
tomwalters@279
|
120 return true;
|
tomwalters@275
|
121 }
|
tomwalters@275
|
122
|
tomwalters@275
|
123 void ModuleFileInput::Process() {
|
tomwalters@278
|
124 if (!file_loaded_)
|
tomwalters@278
|
125 return;
|
tomwalters@279
|
126 sf_count_t read;
|
tomwalters@275
|
127 vector<float> buffer;
|
tomwalters@275
|
128 buffer.resize(buffer_length_ * audio_channels_);
|
tomwalters@275
|
129
|
tomwalters@275
|
130 while (true) {
|
tomwalters@279
|
131 // Read buffersize bytes into buffer
|
tomwalters@279
|
132 read = sf_readf_float(file_handle_, &buffer[0], buffer_length_);
|
tomwalters@275
|
133
|
tomwalters@275
|
134 // Place the contents of the buffer into the signal bank
|
tomwalters@275
|
135 int counter = 0;
|
tomwalters@275
|
136 for (int c = 0; c < audio_channels_; ++c) {
|
tomwalters@275
|
137 for (int i = 0; i < read; ++i) {
|
tomwalters@275
|
138 output_.set_sample(c, i, buffer[counter]);
|
tomwalters@275
|
139 ++counter;
|
tomwalters@275
|
140 }
|
tomwalters@275
|
141 }
|
tomwalters@275
|
142
|
tomwalters@279
|
143 // If the number of saples read is less than the buffer length, the end
|
tomwalters@279
|
144 // of the file has been reached.
|
tomwalters@279
|
145 if (read < buffer_length_) {
|
tomwalters@279
|
146 // Zero samples at end
|
tomwalters@279
|
147 for (int c = 0; c < audio_channels_; ++c) {
|
tomwalters@275
|
148 for (int i = read; i < buffer_length_; ++i) {
|
tomwalters@275
|
149 output_.set_sample(c, i, 0.0f);
|
tomwalters@275
|
150 }
|
tomwalters@275
|
151 }
|
tomwalters@279
|
152 // When we're past the end of the buffer, stop looping.
|
tomwalters@279
|
153 if (read == 0)
|
tomwalters@275
|
154 break;
|
tomwalters@279
|
155 }
|
tomwalters@275
|
156
|
tomwalters@279
|
157 // Update time
|
tomwalters@279
|
158 output_.set_start_time(file_position_samples_);
|
tomwalters@279
|
159 file_position_samples_ += read;
|
tomwalters@275
|
160 PushOutput();
|
tomwalters@275
|
161 }
|
tomwalters@275
|
162 }
|
tomwalters@275
|
163 } // namespace aimc
|