// LAME test program // // Copyright (c) 2010 Robert Hegemann // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include class PcmGenerator { float* m_buffer_ch0; float* m_buffer_ch1; int m_size; float m_a; float m_b; static double random() { int const range_max = 32768; int const range_min = -32767; return (double)rand() / (RAND_MAX + 1) * (range_max - range_min) + range_min; } PcmGenerator( PcmGenerator const& ); PcmGenerator& operator = ( PcmGenerator const& ); public: explicit PcmGenerator(int size) { m_size = size >= 0 ? size : 0; m_buffer_ch0 = new float [m_size]; m_buffer_ch1 = new float [m_size]; m_a = 0; m_b = 0; advance(0); } ~PcmGenerator() { delete[] m_buffer_ch0; delete[] m_buffer_ch1; } float const* ch0() const { return m_buffer_ch0; } float const* ch1() const { return m_buffer_ch1; } void advance( int x ) { float a = m_a; float b = m_b; for (int i = 0; i < m_size; ++i) { a += 10; if (a > 32768) a = random(); b -= 10; if (b < -32767) b = random(); m_buffer_ch0[i] = a; m_buffer_ch1[i] = b; } m_a = a; m_b = b; } }; class OutFile { FILE* m_file_handle; public: OutFile() : m_file_handle(0) {} explicit OutFile(wchar_t const* filename) : m_file_handle(0) { m_file_handle = _wfopen(filename, L"wb"); } ~OutFile() { close(); } bool isOpen() const { return 0 != m_file_handle; } void close() { if (isOpen()) { fclose(m_file_handle); m_file_handle = 0; } } void write(unsigned char const* data, int n) { fwrite(data, 1, n, m_file_handle); } }; class Lame { lame_t m_gf; bool m_init_params_called; void ensureInitialized() { if (isOpen()) { if (!m_init_params_called) { m_init_params_called = true; lame_init_params(m_gf); } } } public: Lame() : m_gf( lame_init() ) , m_init_params_called( false ) {} ~Lame() { close(); } void close() { if (isOpen()) { lame_close(m_gf); m_gf = 0; } } bool isOpen() const { return m_gf != 0; } operator lame_t () const { return m_gf; } void setInSamplerate( int rate ) { lame_set_in_samplerate(m_gf, rate); } void setOutSamplerate( int rate ) { lame_set_out_samplerate(m_gf, rate); } void setNumChannels( int num_channel ) { lame_set_num_channels(m_gf, num_channel); } int encode(float const* ch0, float const* ch1, int n_in, unsigned char* out_buffer, int m_out_free) { ensureInitialized(); return lame_encode_buffer_float(m_gf, ch0, ch1, n_in, out_buffer, m_out_free); } int flush(unsigned char* out_buffer, int m_out_free) { ensureInitialized(); return lame_encode_flush(m_gf, out_buffer, m_out_free); } int getLameTag(unsigned char* out_buffer, int m_out_free) { ensureInitialized(); return lame_get_lametag_frame(m_gf, out_buffer, m_out_free); } }; class OutBuffer { unsigned char* m_data; int m_size; int m_used; OutBuffer( OutBuffer const& ); OutBuffer& operator = ( OutBuffer const& ); public: OutBuffer() { m_size = 1000 * 1000; m_data = new unsigned char[ m_size ]; m_used = 0; } ~OutBuffer() { delete[] m_data; } void advance( int i ) { m_used += i; } int used() const { return m_used; } int unused() const { return m_size - m_used; } unsigned char* current() { return m_data + m_used; } unsigned char* begin() { return m_data; } }; void generateFile(wchar_t const* filename, size_t n) { int const chunk = 1152; PcmGenerator src(chunk); OutFile mp3_stream( filename ); if (!mp3_stream.isOpen()) return; Lame lame; if (!lame.isOpen()) return; OutBuffer mp3_stream_buffer; int rc = 0; lame.setInSamplerate(44100); lame.setOutSamplerate(44100); lame.setNumChannels(2); while (n > 0) { int const m = n < chunk ? n : chunk; if ( n < chunk ) n = 0; else n -= chunk; rc = lame.encode(src.ch0(), src.ch1(), m, mp3_stream_buffer.current(), mp3_stream_buffer.unused()); wprintf(L"rc=%d %d %d\n",rc,mp3_stream_buffer.used(),mp3_stream_buffer.unused()); if (rc < 0) return; mp3_stream_buffer.advance( rc ); src.advance(m); } rc = lame.flush(mp3_stream_buffer.current(), mp3_stream_buffer.unused()); wprintf(L"flush rc=%d\n",rc); if (rc < 0) return; mp3_stream_buffer.advance( rc ); int lametag_size = lame.getLameTag(0,0); wprintf(L"lametag_size=%d\n",lametag_size); rc = lame.getLameTag(mp3_stream_buffer.begin(), lametag_size); wprintf(L"rc=%d\n",rc); if (rc < 0) return; mp3_stream.write(mp3_stream_buffer.begin(), mp3_stream_buffer.used()); lame.close(); } int wmain(int argc, wchar_t** argv) { if (argc != 3) { wprintf(L"usage: %ws \n", argv[0]); return -1; } wprintf(L"open file %ws\n", argv[1]); int n = _wtoi(argv[2]); wprintf(L"synthesize %d samples long mp3 file\n",n); generateFile(argv[1], n); return 0; }