OpenShot Audio Library | OpenShotAudio: juce_LAMEEncoderAudioFormat.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.2

Loading...
Searching...
No Matches
juce_LAMEEncoderAudioFormat.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11 Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12 27th April 2017).
13
14 End User License Agreement: www.juce.com/juce-5-licence
15 Privacy Policy: www.juce.com/juce-5-privacy-policy
16
17 Or: You may also use this code under the terms of the GPL v3 (see
18 www.gnu.org/licenses).
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
30#if JUCE_USE_LAME_AUDIO_FORMAT
31
32class LAMEEncoderAudioFormat::Writer : public AudioFormatWriter
33{
34public:
35 Writer (OutputStream* destStream, const String& formatName,
36 const File& appFile, int vbr, int cbr,
37 double sampleRate, unsigned int numberOfChannels,
38 int bitsPerSample, const StringPairArray& metadata)
39 : AudioFormatWriter (destStream, formatName, sampleRate,
40 numberOfChannels, (unsigned int) bitsPerSample),
41 vbrLevel (vbr), cbrBitrate (cbr)
42 {
43 WavAudioFormat wavFormat;
44
45 if (auto* out = tempWav.getFile().createOutputStream())
46 {
47 writer.reset (wavFormat.createWriterFor (out, sampleRate, numChannels,
48 bitsPerSample, metadata, 0));
49
50 args.add (appFile.getFullPathName());
51
52 args.add ("--quiet");
53
54 if (cbrBitrate == 0)
55 {
56 args.add ("--vbr-new");
57 args.add ("-V");
58 args.add (String (vbrLevel));
59 }
60 else
61 {
62 args.add ("--cbr");
63 args.add ("-b");
64 args.add (String (cbrBitrate));
65 }
66
67 addMetadataArg (metadata, "id3title", "--tt");
68 addMetadataArg (metadata, "id3artist", "--ta");
69 addMetadataArg (metadata, "id3album", "--tl");
70 addMetadataArg (metadata, "id3comment", "--tc");
71 addMetadataArg (metadata, "id3date", "--ty");
72 addMetadataArg (metadata, "id3genre", "--tg");
73 addMetadataArg (metadata, "id3trackNumber", "--tn");
74 }
75 }
76
77 void addMetadataArg (const StringPairArray& metadata, const char* key, const char* lameFlag)
78 {
79 auto value = metadata.getValue (key, {});
80
81 if (value.isNotEmpty())
82 {
83 args.add (lameFlag);
84 args.add (value);
85 }
86 }
87
88 ~Writer()
89 {
90 if (writer != nullptr)
91 {
92 writer = nullptr;
93
94 if (! convertToMP3())
95 convertToMP3(); // try again
96 }
97 }
98
99 bool write (const int** samplesToWrite, int numSamples)
100 {
101 return writer != nullptr && writer->write (samplesToWrite, numSamples);
102 }
103
104private:
105 int vbrLevel, cbrBitrate;
106 TemporaryFile tempWav { ".wav" };
107 std::unique_ptr<AudioFormatWriter> writer;
108 StringArray args;
109
110 bool runLameChildProcess (const TemporaryFile& tempMP3, const StringArray& processArgs) const
111 {
112 ChildProcess cp;
113
114 if (cp.start (processArgs))
115 {
116 auto childOutput = cp.readAllProcessOutput();
117 DBG (childOutput); ignoreUnused (childOutput);
118
119 cp.waitForProcessToFinish (10000);
120 return tempMP3.getFile().getSize() > 0;
121 }
122
123 return false;
124 }
125
126 bool convertToMP3() const
127 {
128 TemporaryFile tempMP3 (".mp3");
129
130 StringArray args2 (args);
131 args2.add (tempWav.getFile().getFullPathName());
132 args2.add (tempMP3.getFile().getFullPathName());
133
134 DBG (args2.joinIntoString (" "));
135
136 if (runLameChildProcess (tempMP3, args2))
137 {
138 FileInputStream fis (tempMP3.getFile());
139
140 if (fis.openedOk() && output->writeFromInputStream (fis, -1) > 0)
141 {
142 output->flush();
143 return true;
144 }
145 }
146
147 return false;
148 }
149
150 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Writer)
151};
152
153//==============================================================================
154LAMEEncoderAudioFormat::LAMEEncoderAudioFormat (const File& lameApplication)
155 : AudioFormat ("MP3 file", ".mp3"),
156 lameApp (lameApplication)
157{
158}
159
160LAMEEncoderAudioFormat::~LAMEEncoderAudioFormat()
161{
162}
163
164bool LAMEEncoderAudioFormat::canHandleFile (const File&)
165{
166 return false;
167}
168
169Array<int> LAMEEncoderAudioFormat::getPossibleSampleRates()
170{
171 return { 32000, 44100, 48000 };
172}
173
174Array<int> LAMEEncoderAudioFormat::getPossibleBitDepths()
175{
176 return { 16 };
177}
178
179bool LAMEEncoderAudioFormat::canDoStereo() { return true; }
180bool LAMEEncoderAudioFormat::canDoMono() { return true; }
181bool LAMEEncoderAudioFormat::isCompressed() { return true; }
182
183StringArray LAMEEncoderAudioFormat::getQualityOptions()
184{
185 static const char* vbrOptions[] = { "VBR quality 0 (best)", "VBR quality 1", "VBR quality 2", "VBR quality 3",
186 "VBR quality 4 (normal)", "VBR quality 5", "VBR quality 6", "VBR quality 7",
187 "VBR quality 8", "VBR quality 9 (smallest)", nullptr };
188 StringArray opts (vbrOptions);
189
190 const int cbrRates[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };
191
192 for (int i = 0; i < numElementsInArray (cbrRates); ++i)
193 opts.add (String (cbrRates[i]) + " Kb/s CBR");
194
195 return opts;
196}
197
198AudioFormatReader* LAMEEncoderAudioFormat::createReaderFor (InputStream*, const bool)
199{
200 return nullptr;
201}
202
203AudioFormatWriter* LAMEEncoderAudioFormat::createWriterFor (OutputStream* streamToWriteTo,
204 double sampleRateToUse,
205 unsigned int numberOfChannels,
206 int bitsPerSample,
207 const StringPairArray& metadataValues,
208 int qualityOptionIndex)
209{
210 if (streamToWriteTo == nullptr)
211 return nullptr;
212
213 int vbr = 4;
214 int cbr = 0;
215
216 const String qual (getQualityOptions() [qualityOptionIndex]);
217
218 if (qual.contains ("VBR"))
219 vbr = qual.retainCharacters ("0123456789").getIntValue();
220 else
221 cbr = qual.getIntValue();
222
223 return new Writer (streamToWriteTo, getFormatName(), lameApp, vbr, cbr,
224 sampleRateToUse, numberOfChannels, bitsPerSample, metadataValues);
225}
226
227#endif
228
229} // namespace juce