Mercurial > hg > aimc
comparison trunk/src/Modules/Output/FileOutputHTK.cc @ 277:6b4921704eb1
- Ported over HTK file output
- Added some more meat to the Slaney IIR gammatone implementation
- Ported over the AIM-MAT sf2003 parabola strobe algorithm
- Finished making the SAI implementation compile
- Ported over the strobe list class (now uses STL deques internally)
author | tomwalters |
---|---|
date | Thu, 18 Feb 2010 16:55:40 +0000 |
parents | |
children | 5b8b9ea1218a |
comparison
equal
deleted
inserted
replaced
276:a57b29e373c7 | 277:6b4921704eb1 |
---|---|
1 // Copyright 2006-2010, Thomas Walters | |
2 // | |
3 // AIM-C: A C++ implementation of the Auditory Image Model | |
4 // http://www.acousticscale.org/AIMC | |
5 // | |
6 // This program is free software: you can redistribute it and/or modify | |
7 // it under the terms of the GNU General Public License as published by | |
8 // the Free Software Foundation, either version 3 of the License, or | |
9 // (at your option) any later version. | |
10 // | |
11 // This program is distributed in the hope that it will be useful, | |
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 // GNU General Public License for more details. | |
15 // | |
16 // You should have received a copy of the GNU General Public License | |
17 // along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 /*! | |
20 * \file | |
21 * \brief File output in the HTK format. | |
22 * | |
23 * \author Tom Walters <tom@acousticscale.org> | |
24 * \author Willem van Engen <cnbh@willem.engen.nl> | |
25 * \date created 2006/10/30 | |
26 * \version \$Id$ | |
27 */ | |
28 | |
29 #ifdef _WINDOWS | |
30 # include <direct.h> // for _mkdir&_rmdir | |
31 #else | |
32 # include <sys/types.h> | |
33 # include <dirent.h> // for opendir&friends | |
34 #endif | |
35 #include <stdio.h> | |
36 #include <string.h> | |
37 #include <cmath> | |
38 | |
39 #include "Modules/Output/FileOutputHTK.h" | |
40 | |
41 namespace aimc { | |
42 FileOutputHTK::FileOutputHTK(Parameters *params) : Module(params) { | |
43 file_handle_ = NULL; | |
44 header_written_ = false; | |
45 filename_[0] = '\0'; | |
46 frame_period_ms_ = 0.0f; | |
47 } | |
48 | |
49 FileOutputHTK::~FileOutputHTK() { | |
50 if (file_handle_ != NULL) | |
51 CloseFile(); | |
52 } | |
53 | |
54 bool FileOutputHTK::OpenFile(const char* filename, float frame_period_ms) { | |
55 if (file_handle_ != NULL) { | |
56 LOG_ERROR(_T("Couldn't open output file. A file is already open.")); | |
57 return false; | |
58 } | |
59 | |
60 // Check that the output file exists and is writeable | |
61 if ((file_handle_ = fopen(filename, "wb"))==NULL ) { | |
62 LOG_ERROR(_T("Couldn't open output file '%s' for writing."), filename); | |
63 return false; | |
64 } | |
65 strcpy(filename_, filename); | |
66 sample_count_ = 0; | |
67 frame_period_ms_ = frame_period_ms; | |
68 header_written_ = false; | |
69 return true; | |
70 } | |
71 | |
72 bool FileOutputHTK::InitializeInternal(const SignalBank &input) { | |
73 if (file_handle_ == NULL) { | |
74 LOG_ERROR(_T("Couldn't initialize file output. " | |
75 "Please call FileOutputHTK::OpenFile first")); | |
76 return false; | |
77 } | |
78 if (header_written_) { | |
79 LOG_ERROR(_T("A header has already been written on the output file." | |
80 "Please call FileOutputHTK::CloseFile to close that file, " | |
81 "and FileOutputHTK::OpenFile to open an new one before " | |
82 "calling FileOutputHTK::Initialize again.")); | |
83 return false; | |
84 } | |
85 channel_count_ = input.channel_count(); | |
86 buffer_length_ = input.buffer_length(); | |
87 WriteHeader(channel_count_ * buffer_length_, frame_period_ms_); | |
88 return true; | |
89 } | |
90 | |
91 void FileOutputHTK::ResetInternal() { | |
92 if (file_handle_ != NULL && !header_written_) { | |
93 WriteHeader(channel_count_ * buffer_length_, frame_period_ms_); | |
94 } | |
95 } | |
96 | |
97 void FileOutputHTK::WriteHeader(int num_elements, float period_ms) { | |
98 if (header_written_) | |
99 return; | |
100 | |
101 /* HTK format file: (taken from the HTK book - section 5.10.1) | |
102 * Header: 12 bytes in total, contains: | |
103 * sample_count - number of samples in file (4-byte integer)(long) | |
104 * sample_period - sample period in 100ns units (4-byte integer)(long) | |
105 * sample_size - number of bytes per sample (2-byte integer)(short) | |
106 * parameter_kind - a code indicating the sample kind (2-byte integer)(short) | |
107 */ | |
108 | |
109 // To be filled in when the file is done | |
110 int32_t sample_count = 0; | |
111 | |
112 int32_t sample_period = floor(1e4 * period_ms); | |
113 int16_t sample_size = num_elements * sizeof(float); | |
114 | |
115 // User-defined coefficients with energy term | |
116 int16_t parameter_kind = H_USER + H_E; | |
117 | |
118 // Fix endianness | |
119 sample_count = ByteSwap32(sample_count); | |
120 sample_period = ByteSwap32(sample_period); | |
121 sample_size = ByteSwap16(sample_size); | |
122 parameter_kind = ByteSwap16(parameter_kind); | |
123 | |
124 // Enter header values. sample_count is a dummy value which is filled in on | |
125 // file close | |
126 fwrite(&sample_count, sizeof(sample_count), 1, file_handle_); | |
127 fwrite(&sample_period, sizeof(sample_period), 1, file_handle_); | |
128 fwrite(&sample_size, sizeof(sample_size), 1, file_handle_); | |
129 fwrite(¶meter_kind, sizeof(parameter_kind), 1, file_handle_); | |
130 fflush(file_handle_); | |
131 | |
132 header_written_ = true; | |
133 } | |
134 | |
135 | |
136 void FileOutputHTK::Process(const SignalBank &input) { | |
137 if (file_handle_ == NULL) { | |
138 LOG_ERROR(_T("Couldn't process file output. No file is open." | |
139 "Please call FileOutputHTK::OpenFile first")); | |
140 return; | |
141 } | |
142 | |
143 if (!header_written_) { | |
144 LOG_ERROR(_T("No header has been written on the output file yet. Please" | |
145 "call FileOutputHTK::Initialize() before calling " | |
146 "FileOutputHTK::Process()")); | |
147 return; | |
148 } | |
149 float s; | |
150 | |
151 for (int ch = 0; ch < input.channel_count(); ch++) { | |
152 for (int i = 0; i < input.buffer_length(); i++) { | |
153 s = input.sample(ch, i); | |
154 s = ByteSwapFloat(s); | |
155 fwrite(&s, sizeof(float), 1, file_handle_); | |
156 } | |
157 } | |
158 sample_count_++; | |
159 } | |
160 | |
161 bool FileOutputHTK::CloseFile() { | |
162 if (file_handle_ == NULL) | |
163 return false; | |
164 | |
165 // Write the first 4 bytes of the file | |
166 // with how many samples there are in the file | |
167 fflush(file_handle_); | |
168 rewind(file_handle_); | |
169 fflush(file_handle_); | |
170 int32_t samples = sample_count_; | |
171 samples = ByteSwap32(samples); | |
172 fwrite(&samples, sizeof(samples), 1, file_handle_); | |
173 | |
174 // And close the file | |
175 fclose(file_handle_); | |
176 file_handle_ = NULL; | |
177 return true; | |
178 } | |
179 | |
180 float FileOutputHTK::ByteSwapFloat(float d) { | |
181 // Endianness fix | |
182 float a; | |
183 unsigned char *dst = (unsigned char *)&a; | |
184 unsigned char *src = (unsigned char *)&d; | |
185 | |
186 dst[0] = src[3]; | |
187 dst[1] = src[2]; | |
188 dst[2] = src[1]; | |
189 dst[3] = src[0]; | |
190 | |
191 return a; | |
192 } | |
193 } //namespace aimc | |
194 |