xref: /third_party/lame/test/lame_test.cpp (revision 159b3361)
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
25class 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
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
43public:
44
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
55  ~PcmGenerator()
56  {
57    delete[] m_buffer_ch0;
58    delete[] m_buffer_ch1;
59  }
60
61  float const* ch0() const { return m_buffer_ch0; }
62  float const* ch1() const { return m_buffer_ch1; }
63
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
80class OutFile
81{
82  FILE* m_file_handle;
83
84public:
85  OutFile()
86    : m_file_handle(0)
87  {}
88
89  explicit OutFile(wchar_t const* filename)
90    : m_file_handle(0)
91  {
92    m_file_handle = _wfopen(filename, L"wb");
93  }
94
95  ~OutFile()
96  {
97    close();
98  }
99
100  bool isOpen() const {
101    return 0 != m_file_handle;
102  }
103
104  void close() {
105    if (isOpen()) {
106      fclose(m_file_handle);
107      m_file_handle = 0;
108    }
109  }
110
111  void write(unsigned char const* data, int n) {
112    fwrite(data, 1, n, m_file_handle);
113  }
114};
115
116class Lame
117{
118  lame_t m_gf;
119  bool m_init_params_called;
120
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
130public:
131
132  Lame()
133    : m_gf( lame_init() )
134    , m_init_params_called( false )
135  {}
136
137  ~Lame()
138  {
139    close();
140  }
141
142  void close() {
143    if (isOpen()) {
144      lame_close(m_gf);
145      m_gf = 0;
146    }
147  }
148
149  bool isOpen() const {
150    return m_gf != 0;
151  }
152
153  operator lame_t () const {
154    return m_gf;
155  }
156
157  void setInSamplerate( int rate ) {
158    lame_set_in_samplerate(m_gf, rate);
159  }
160
161  void setOutSamplerate( int rate ) {
162    lame_set_out_samplerate(m_gf, rate);
163  }
164
165  void setNumChannels( int num_channel ) {
166    lame_set_num_channels(m_gf, num_channel);
167  }
168
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
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
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
186class 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
195public:
196
197  OutBuffer()
198  {
199    m_size = 1000 * 1000;
200    m_data = new unsigned char[ m_size ];
201    m_used = 0;
202  }
203
204  ~OutBuffer()
205  {
206    delete[] m_data;
207  }
208
209  void advance( int i ) {
210    m_used += i;
211  }
212
213  int used() const {
214    return m_used;
215  }
216
217  int unused() const {
218    return m_size - m_used;
219  }
220
221  unsigned char* current() { return m_data + m_used; }
222  unsigned char* begin()   { return m_data; }
223};
224
225void 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
271int 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