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