The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
7.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #if JUCE_USE_LAME_AUDIO_FORMAT
  19. class LAMEEncoderAudioFormat::Writer : public AudioFormatWriter
  20. {
  21. public:
  22. Writer (OutputStream* destStream, const String& formatName,
  23. const File& lameApp, int vbr, int cbr,
  24. double sampleRate, unsigned int numberOfChannels,
  25. unsigned int bitsPerSample, const StringPairArray& metadata)
  26. : AudioFormatWriter (destStream, formatName, sampleRate,
  27. numberOfChannels, bitsPerSample),
  28. vbrLevel (vbr), cbrBitrate (cbr),
  29. tempWav (".wav")
  30. {
  31. WavAudioFormat wavFormat;
  32. if (FileOutputStream* out = tempWav.getFile().createOutputStream())
  33. {
  34. writer = wavFormat.createWriterFor (out, sampleRate, numChannels,
  35. bitsPerSample, metadata, 0);
  36. args.add (lameApp.getFullPathName());
  37. args.add ("--quiet");
  38. if (cbrBitrate == 0)
  39. {
  40. args.add ("-vbr-new");
  41. args.add ("-V");
  42. args.add (String (vbrLevel));
  43. }
  44. else
  45. {
  46. args.add ("--cbr");
  47. args.add ("-b");
  48. args.add (String (cbrBitrate));
  49. }
  50. addMetadataArg (metadata, "id3title", "--tt");
  51. addMetadataArg (metadata, "id3artist", "--ta");
  52. addMetadataArg (metadata, "id3album", "--tl");
  53. addMetadataArg (metadata, "id3comment", "--tc");
  54. addMetadataArg (metadata, "id3date", "--ty");
  55. addMetadataArg (metadata, "id3genre", "--tg");
  56. addMetadataArg (metadata, "id3trackNumber", "--tn");
  57. }
  58. }
  59. void addMetadataArg (const StringPairArray& metadata, const char* key, const char* lameFlag)
  60. {
  61. const String value (metadata.getValue (key, String::empty));
  62. if (value.isNotEmpty())
  63. {
  64. args.add (lameFlag);
  65. args.add (value);
  66. }
  67. }
  68. ~Writer()
  69. {
  70. if (writer != nullptr)
  71. {
  72. writer = nullptr;
  73. if (! convertToMP3())
  74. convertToMP3(); // try again
  75. }
  76. }
  77. bool write (const int** samplesToWrite, int numSamples)
  78. {
  79. return writer != nullptr && writer->write (samplesToWrite, numSamples);
  80. }
  81. private:
  82. int vbrLevel, cbrBitrate;
  83. TemporaryFile tempWav;
  84. ScopedPointer<AudioFormatWriter> writer;
  85. StringArray args;
  86. bool convertToMP3() const
  87. {
  88. TemporaryFile tempMP3 (".mp3");
  89. StringArray args2 (args);
  90. args2.add (tempWav.getFile().getFullPathName());
  91. args2.add (tempMP3.getFile().getFullPathName());
  92. ChildProcess cp;
  93. DBG (args2.joinIntoString(" "));
  94. if (cp.start (args2))
  95. {
  96. String childOutput (cp.readAllProcessOutput());
  97. DBG (childOutput);
  98. if (tempMP3.getFile().getSize() > 0)
  99. {
  100. FileInputStream fis (tempMP3.getFile());
  101. if (fis.openedOk() && output->writeFromInputStream (fis, -1) > 0)
  102. {
  103. output->flush();
  104. return true;
  105. }
  106. }
  107. }
  108. return false;
  109. }
  110. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Writer)
  111. };
  112. //==============================================================================
  113. static const char* const lameFormatName = "MP3 file";
  114. static const char* const lameExtensions[] = { ".mp3", nullptr };
  115. LAMEEncoderAudioFormat::LAMEEncoderAudioFormat (const File& lameApplication)
  116. : AudioFormat (TRANS (lameFormatName), StringArray (lameExtensions)),
  117. lameApp (lameApplication)
  118. {
  119. }
  120. LAMEEncoderAudioFormat::~LAMEEncoderAudioFormat()
  121. {
  122. }
  123. bool LAMEEncoderAudioFormat::canHandleFile (const File&)
  124. {
  125. return false;
  126. }
  127. Array<int> LAMEEncoderAudioFormat::getPossibleSampleRates()
  128. {
  129. const int rates[] = { 32000, 44100, 48000, 0 };
  130. return Array <int> (rates);
  131. }
  132. Array<int> LAMEEncoderAudioFormat::getPossibleBitDepths()
  133. {
  134. const int depths[] = { 16, 0 };
  135. return Array <int> (depths);
  136. }
  137. bool LAMEEncoderAudioFormat::canDoStereo() { return true; }
  138. bool LAMEEncoderAudioFormat::canDoMono() { return true; }
  139. bool LAMEEncoderAudioFormat::isCompressed() { return true; }
  140. StringArray LAMEEncoderAudioFormat::getQualityOptions()
  141. {
  142. const char* vbrOptions[] = { "VBR quality 0 (best)", "VBR quality 1", "VBR quality 2", "VBR quality 3",
  143. "VBR quality 4 (normal)", "VBR quality 5", "VBR quality 6", "VBR quality 7", "VBR quality 8",
  144. "VBR quality 9 (smallest)",
  145. nullptr };
  146. StringArray opts (vbrOptions);
  147. const int cbrRates[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };
  148. for (int i = 0; i < numElementsInArray (cbrRates); ++i)
  149. opts.add (String (cbrRates[i]) + " Kb/s CBR");
  150. return opts;
  151. }
  152. AudioFormatReader* LAMEEncoderAudioFormat::createReaderFor (InputStream*, const bool)
  153. {
  154. return nullptr;
  155. }
  156. AudioFormatWriter* LAMEEncoderAudioFormat::createWriterFor (OutputStream* streamToWriteTo,
  157. double sampleRateToUse,
  158. unsigned int numberOfChannels,
  159. int bitsPerSample,
  160. const StringPairArray& metadataValues,
  161. int qualityOptionIndex)
  162. {
  163. int vbr = 4;
  164. int cbr = 0;
  165. const String qual (getQualityOptions() [qualityOptionIndex]);
  166. if (qual.contains ("VBR"))
  167. vbr = qual.retainCharacters ("0123456789").getIntValue();
  168. else
  169. cbr = qual.getIntValue();
  170. return new Writer (streamToWriteTo, getFormatName(), lameApp, vbr, cbr,
  171. sampleRateToUse, numberOfChannels, bitsPerSample, metadataValues);
  172. }
  173. #endif