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