lame_test.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. #include <lame.h>
  20. #include <wchar.h>
  21. #include <stdlib.h>
  22. class PcmGenerator
  23. {
  24. float* m_buffer_ch0;
  25. float* m_buffer_ch1;
  26. int m_size;
  27. float m_a;
  28. float m_b;
  29. double random()
  30. {
  31. int const range_max = 32768;
  32. int const range_min = -32767;
  33. return (double)rand() / (RAND_MAX + 1) * (range_max - range_min) + range_min;
  34. }
  35. public:
  36. explicit PcmGenerator(int size)
  37. {
  38. m_size = size >= 0 ? size : 0;
  39. m_buffer_ch0 = new float [m_size];
  40. m_buffer_ch1 = new float [m_size];
  41. m_a = 0;
  42. m_b = 0;
  43. advance(0);
  44. }
  45. ~PcmGenerator()
  46. {
  47. delete[] m_buffer_ch0;
  48. delete[] m_buffer_ch1;
  49. }
  50. float const* ch0() const { return m_buffer_ch0; }
  51. float const* ch1() const { return m_buffer_ch1; }
  52. void advance( int x ) {
  53. float a = m_a;
  54. float b = m_b;
  55. for (int i = 0; i < m_size; ++i) {
  56. a += 10;
  57. if (a > 32768) a = random();
  58. b -= 10;
  59. if (b < -32767) b = random();
  60. m_buffer_ch0[i] = a;
  61. m_buffer_ch1[i] = b;
  62. }
  63. m_a = a;
  64. m_b = b;
  65. }
  66. };
  67. class OutFile
  68. {
  69. FILE* m_file_handle;
  70. public:
  71. OutFile()
  72. : m_file_handle(0)
  73. {}
  74. explicit OutFile(wchar_t const* filename)
  75. : m_file_handle(0)
  76. {
  77. m_file_handle = _wfopen(filename, L"wb");
  78. }
  79. ~OutFile()
  80. {
  81. close();
  82. }
  83. bool isOpen() const {
  84. return 0 != m_file_handle;
  85. }
  86. void close() {
  87. if (isOpen()) {
  88. fclose(m_file_handle);
  89. m_file_handle = 0;
  90. }
  91. }
  92. void write(unsigned char const* data, int n) {
  93. fwrite(data, 1, n, m_file_handle);
  94. }
  95. };
  96. class Lame
  97. {
  98. lame_t m_gf;
  99. bool m_init_params_called;
  100. void ensureInitialized() {
  101. if (isOpen()) {
  102. if (!m_init_params_called) {
  103. m_init_params_called = true;
  104. lame_init_params(m_gf);
  105. }
  106. }
  107. }
  108. public:
  109. Lame()
  110. : m_gf( lame_init() )
  111. , m_init_params_called( false )
  112. {}
  113. ~Lame()
  114. {
  115. close();
  116. }
  117. void close() {
  118. if (isOpen()) {
  119. lame_close(m_gf);
  120. m_gf = 0;
  121. }
  122. }
  123. bool isOpen() const {
  124. return m_gf != 0;
  125. }
  126. operator lame_t () {
  127. return m_gf;
  128. }
  129. operator lame_t () const {
  130. return m_gf;
  131. }
  132. void setInSamplerate( int rate ) {
  133. lame_set_in_samplerate(m_gf, rate);
  134. }
  135. void setOutSamplerate( int rate ) {
  136. lame_set_out_samplerate(m_gf, rate);
  137. }
  138. void setNumChannels( int num_channel ) {
  139. lame_set_num_channels(m_gf, num_channel);
  140. }
  141. int encode(float const* ch0, float const* ch1, int n_in, unsigned char* out_buffer, int m_out_free) {
  142. ensureInitialized();
  143. return lame_encode_buffer_float(m_gf, ch0, ch1, n_in, out_buffer, m_out_free);
  144. }
  145. int flush(unsigned char* out_buffer, int m_out_free) {
  146. ensureInitialized();
  147. return lame_encode_flush(m_gf, out_buffer, m_out_free);
  148. }
  149. int getLameTag(unsigned char* out_buffer, int m_out_free) {
  150. ensureInitialized();
  151. return lame_get_lametag_frame(m_gf, out_buffer, m_out_free);
  152. }
  153. };
  154. class OutBuffer
  155. {
  156. unsigned char* m_data;
  157. int m_size;
  158. int m_used;
  159. public:
  160. OutBuffer()
  161. {
  162. m_size = 1000 * 1000;
  163. m_data = new unsigned char[ m_size ];
  164. m_used = 0;
  165. }
  166. ~OutBuffer()
  167. {
  168. delete[] m_data;
  169. }
  170. void advance( int i ) {
  171. m_used += i;
  172. }
  173. int used() const {
  174. return m_used;
  175. }
  176. int unused() const {
  177. return m_size - m_used;
  178. }
  179. unsigned char* current() { return m_data + m_used; }
  180. unsigned char* begin() { return m_data; }
  181. };
  182. void generateFile(wchar_t const* filename, size_t n)
  183. {
  184. int const chunk = 1152;
  185. PcmGenerator src(chunk);
  186. OutFile mp3_stream( filename );
  187. if (!mp3_stream.isOpen()) return;
  188. Lame lame;
  189. if (!lame.isOpen()) return;
  190. OutBuffer mp3_stream_buffer;
  191. int rc = 0;
  192. lame.setInSamplerate(44100);
  193. lame.setOutSamplerate(44100);
  194. lame.setNumChannels(2);
  195. while (n > 0) {
  196. int const m = n < chunk ? n : chunk;
  197. if ( n < chunk ) n = 0; else n -= chunk;
  198. rc = lame.encode(src.ch0(), src.ch1(), m, mp3_stream_buffer.current(), mp3_stream_buffer.unused());
  199. wprintf(L"rc=%d %d %d\n",rc,mp3_stream_buffer.used(),mp3_stream_buffer.unused());
  200. if (rc < 0) return;
  201. mp3_stream_buffer.advance( rc );
  202. src.advance(m);
  203. }
  204. rc = lame.flush(mp3_stream_buffer.current(), mp3_stream_buffer.unused());
  205. wprintf(L"flush rc=%d\n",rc);
  206. if (rc < 0) return;
  207. mp3_stream_buffer.advance( rc );
  208. int lametag_size = lame.getLameTag(0,0);
  209. wprintf(L"lametag_size=%d\n",lametag_size);
  210. rc = lame.getLameTag(mp3_stream_buffer.begin(), lametag_size);
  211. wprintf(L"rc=%d\n",rc);
  212. if (rc < 0) return;
  213. mp3_stream.write(mp3_stream_buffer.begin(), mp3_stream_buffer.used());
  214. lame.close();
  215. }
  216. int wmain(int argc, wchar_t** argv)
  217. {
  218. if (argc != 3) {
  219. wprintf(L"usage: %ws <filename> <number pcm samples>\n", argv[0]);
  220. return -1;
  221. }
  222. wprintf(L"open file %ws\n", argv[1]);
  223. int n = _wtoi(argv[2]);
  224. wprintf(L"synthesize %d samples long mp3 file\n",n);
  225. generateFile(argv[1], n);
  226. return 0;
  227. }