1 // LAME test program
2 //
3 // Copyright (c) 2010 Robert Hegemann
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the
17 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 // Boston, MA 02111-1307, USA.
19
20 #include <lame.h>
21 #include <wchar.h>
22 #include <stdlib.h>
23
24
25 class PcmGenerator
26 {
27 float* m_buffer_ch0;
28 float* m_buffer_ch1;
29 int m_size;
30 float m_a;
31 float m_b;
32
random()33 static double random()
34 {
35 int const range_max = 32768;
36 int const range_min = -32767;
37 return (double)rand() / (RAND_MAX + 1) * (range_max - range_min) + range_min;
38 }
39
40 PcmGenerator( PcmGenerator const& );
41 PcmGenerator& operator = ( PcmGenerator const& );
42
43 public:
44
PcmGenerator(int size)45 explicit PcmGenerator(int size)
46 {
47 m_size = size >= 0 ? size : 0;
48 m_buffer_ch0 = new float [m_size];
49 m_buffer_ch1 = new float [m_size];
50 m_a = 0;
51 m_b = 0;
52 advance(0);
53 }
54
~PcmGenerator()55 ~PcmGenerator()
56 {
57 delete[] m_buffer_ch0;
58 delete[] m_buffer_ch1;
59 }
60
ch0() const61 float const* ch0() const { return m_buffer_ch0; }
ch1() const62 float const* ch1() const { return m_buffer_ch1; }
63
advance( int x )64 void advance( int x ) {
65 float a = m_a;
66 float b = m_b;
67 for (int i = 0; i < m_size; ++i) {
68 a += 10;
69 if (a > 32768) a = random();
70 b -= 10;
71 if (b < -32767) b = random();
72 m_buffer_ch0[i] = a;
73 m_buffer_ch1[i] = b;
74 }
75 m_a = a;
76 m_b = b;
77 }
78 };
79
80 class OutFile
81 {
82 FILE* m_file_handle;
83
84 public:
OutFile()85 OutFile()
86 : m_file_handle(0)
87 {}
88
OutFile(wchar_t const* filename)89 explicit OutFile(wchar_t const* filename)
90 : m_file_handle(0)
91 {
92 m_file_handle = _wfopen(filename, L"wb");
93 }
94
~OutFile()95 ~OutFile()
96 {
97 close();
98 }
99
isOpen() const100 bool isOpen() const {
101 return 0 != m_file_handle;
102 }
103
close()104 void close() {
105 if (isOpen()) {
106 fclose(m_file_handle);
107 m_file_handle = 0;
108 }
109 }
110
write(unsigned char const* data, int n)111 void write(unsigned char const* data, int n) {
112 fwrite(data, 1, n, m_file_handle);
113 }
114 };
115
116 class Lame
117 {
118 lame_t m_gf;
119 bool m_init_params_called;
120
ensureInitialized()121 void ensureInitialized() {
122 if (isOpen()) {
123 if (!m_init_params_called) {
124 m_init_params_called = true;
125 lame_init_params(m_gf);
126 }
127 }
128 }
129
130 public:
131
Lame()132 Lame()
133 : m_gf( lame_init() )
134 , m_init_params_called( false )
135 {}
136
~Lame()137 ~Lame()
138 {
139 close();
140 }
141
close()142 void close() {
143 if (isOpen()) {
144 lame_close(m_gf);
145 m_gf = 0;
146 }
147 }
148
isOpen() const149 bool isOpen() const {
150 return m_gf != 0;
151 }
152
operator lame_t() const153 operator lame_t () const {
154 return m_gf;
155 }
156
setInSamplerate( int rate )157 void setInSamplerate( int rate ) {
158 lame_set_in_samplerate(m_gf, rate);
159 }
160
setOutSamplerate( int rate )161 void setOutSamplerate( int rate ) {
162 lame_set_out_samplerate(m_gf, rate);
163 }
164
setNumChannels( int num_channel )165 void setNumChannels( int num_channel ) {
166 lame_set_num_channels(m_gf, num_channel);
167 }
168
encode(float const* ch0, float const* ch1, int n_in, unsigned char* out_buffer, int m_out_free)169 int encode(float const* ch0, float const* ch1, int n_in, unsigned char* out_buffer, int m_out_free) {
170 ensureInitialized();
171 return lame_encode_buffer_float(m_gf, ch0, ch1, n_in, out_buffer, m_out_free);
172 }
173
flush(unsigned char* out_buffer, int m_out_free)174 int flush(unsigned char* out_buffer, int m_out_free) {
175 ensureInitialized();
176 return lame_encode_flush(m_gf, out_buffer, m_out_free);
177 }
178
getLameTag(unsigned char* out_buffer, int m_out_free)179 int getLameTag(unsigned char* out_buffer, int m_out_free) {
180 ensureInitialized();
181 return lame_get_lametag_frame(m_gf, out_buffer, m_out_free);
182 }
183
184 };
185
186 class OutBuffer
187 {
188 unsigned char* m_data;
189 int m_size;
190 int m_used;
191
192 OutBuffer( OutBuffer const& );
193 OutBuffer& operator = ( OutBuffer const& );
194
195 public:
196
OutBuffer()197 OutBuffer()
198 {
199 m_size = 1000 * 1000;
200 m_data = new unsigned char[ m_size ];
201 m_used = 0;
202 }
203
~OutBuffer()204 ~OutBuffer()
205 {
206 delete[] m_data;
207 }
208
advance( int i )209 void advance( int i ) {
210 m_used += i;
211 }
212
used() const213 int used() const {
214 return m_used;
215 }
216
unused() const217 int unused() const {
218 return m_size - m_used;
219 }
220
current()221 unsigned char* current() { return m_data + m_used; }
begin()222 unsigned char* begin() { return m_data; }
223 };
224
generateFile(wchar_t const* filename, size_t n)225 void generateFile(wchar_t const* filename, size_t n)
226 {
227 int const chunk = 1152;
228 PcmGenerator src(chunk);
229
230 OutFile mp3_stream( filename );
231 if (!mp3_stream.isOpen()) return;
232
233 Lame lame;
234 if (!lame.isOpen()) return;
235
236 OutBuffer mp3_stream_buffer;
237 int rc = 0;
238
239 lame.setInSamplerate(44100);
240 lame.setOutSamplerate(44100);
241 lame.setNumChannels(2);
242
243 while (n > 0) {
244 int const m = n < chunk ? n : chunk;
245 if ( n < chunk ) n = 0; else n -= chunk;
246 rc = lame.encode(src.ch0(), src.ch1(), m, mp3_stream_buffer.current(), mp3_stream_buffer.unused());
247 wprintf(L"rc=%d %d %d\n",rc,mp3_stream_buffer.used(),mp3_stream_buffer.unused());
248 if (rc < 0) return;
249 mp3_stream_buffer.advance( rc );
250 src.advance(m);
251 }
252
253 rc = lame.flush(mp3_stream_buffer.current(), mp3_stream_buffer.unused());
254 wprintf(L"flush rc=%d\n",rc);
255 if (rc < 0) return;
256
257 mp3_stream_buffer.advance( rc );
258
259 int lametag_size = lame.getLameTag(0,0);
260 wprintf(L"lametag_size=%d\n",lametag_size);
261
262 rc = lame.getLameTag(mp3_stream_buffer.begin(), lametag_size);
263 wprintf(L"rc=%d\n",rc);
264 if (rc < 0) return;
265
266 mp3_stream.write(mp3_stream_buffer.begin(), mp3_stream_buffer.used());
267
268 lame.close();
269 }
270
271 int wmain(int argc, wchar_t** argv)
272 {
273 if (argc != 3) {
274 wprintf(L"usage: %ws <filename> <number pcm samples>\n", argv[0]);
275 return -1;
276 }
277 wprintf(L"open file %ws\n", argv[1]);
278 int n = _wtoi(argv[2]);
279 wprintf(L"synthesize %d samples long mp3 file\n",n);
280 generateFile(argv[1], n);
281 return 0;
282 }
283