Audacity 3.2.0
ImportWavPack.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4 Audacity(R) is copyright (c) 1999-2021 Audacity Team.
5 SPDX-License-Identifier: GPL-2.0-or-later. See License.txt.
6
7 ImportWavPack.cpp
8
9 Subhradeep Chakraborty
10
11*//****************************************************************//****************************************************************//*******************************************************************/
22
23#include "Import.h"
24#include "ImportPlugin.h"
25
26#include<wx/string.h>
27#include<wx/log.h>
28#include<stdlib.h>
29#include<wavpack/wavpack.h>
30
31#include "Tags.h"
32#include "WaveTrack.h"
33#include "CodeConversions.h"
34#include "ImportUtils.h"
36
37#define DESC XO("WavPack files")
38
39static const auto exts = {
40 wxT("wv")
41};
42
44{
45public:
48
49 wxString GetPluginStringID() override;
51 std::unique_ptr<ImportFileHandle> Open(
52 const FilePath &Filename, AudacityProject*) override;
53};
54
56{
57public:
58 WavPackImportFileHandle(const FilePath &filename, WavpackContext* wavpackContext);
60
63 void Import(ImportProgressListener &progressListener,
64 WaveTrackFactory *trackFactory,
65 TrackHolders &outTracks,
66 Tags *tags) override;
67
68 wxInt32 GetStreamCount() override;
69 const TranslatableStrings &GetStreamInfo() override;
70 void SetStreamUsage(wxInt32 StreamID, bool Use) override;
71
72private:
73 WavpackContext *mWavPackContext;
75 uint32_t mSampleRate;
78 int64_t mNumSamples;
80};
81
82// ============================================================================
83// WavPackImportPlugin
84// ============================================================================
85
88{
89}
90
92{
93}
94
96{
97 return wxT("libwavpack");
98}
99
101{
102 return DESC;
103}
104
105std::unique_ptr<ImportFileHandle> WavPackImportPlugin::Open(const FilePath &filename, AudacityProject*)
106{
107 char errMessage[100]; // To hold possible error message
108 int flags = OPEN_WVC | OPEN_FILE_UTF8 | OPEN_TAGS | OPEN_DSD_AS_PCM | OPEN_NORMALIZE;
109 WavpackContext *wavpackContext = WavpackOpenFileInput(filename, errMessage, flags, 0);
110
111 if (!wavpackContext) {
112 // Some error occured(e.g. File not found or is invalid)
113 wxLogDebug("WavpackOpenFileInput() failed on file %s, error = %s", filename, errMessage);
114 return nullptr;
115 }
116
117 auto handle = std::make_unique<WavPackImportFileHandle>(filename, wavpackContext);
118
119 return std::move(handle);
120}
121
123 std::make_unique< WavPackImportPlugin >()
124};
125
126// ============================================================================
127// WavPackImportFileHandle
128// ============================================================================
129
131 WavpackContext *wavpackContext)
132: ImportFileHandleEx(filename),
133 mWavPackContext(wavpackContext),
134 mNumChannels(WavpackGetNumChannels(mWavPackContext)),
135 mSampleRate(WavpackGetSampleRate(mWavPackContext)),
136 mBitsPerSample(WavpackGetBitsPerSample(mWavPackContext)),
137 mBytesPerSample(WavpackGetBytesPerSample(mWavPackContext)),
138 mNumSamples(WavpackGetNumSamples64(mWavPackContext))
139{
140 if (mBitsPerSample <= 16) {
142 } else if (mBitsPerSample <= 24) {
144 } else {
146 }
147}
148
150{
151 return DESC;
152}
153
155{
156 return 0;
157}
158
160 WaveTrackFactory *trackFactory,
161 TrackHolders &outTracks,
162 Tags *tags)
163{
164 BeginImport();
165
166 const int wavpackMode = WavpackGetMode(mWavPackContext);
167
168 outTracks.clear();
169
170 auto trackList = ImportUtils::NewWaveTrack(
171 *trackFactory,
173 mFormat,
175
176 /* The number of samples to read in each loop */
177 const size_t SAMPLES_TO_READ = (*trackList->Any<WaveTrack>().begin())->GetMaxBlockSize();
178 uint32_t totalSamplesRead = 0;
179
180 {
181 const uint32_t bufferSize = mNumChannels * SAMPLES_TO_READ;
182 ArrayOf<int32_t> wavpackBuffer{ bufferSize };
183 ArrayOf<int16_t> int16Buffer;
184 ArrayOf<float> floatBuffer;
185 uint32_t samplesRead = 0;
186
187 if (mFormat == int16Sample) {
188 int16Buffer.reinit(bufferSize);
189 } else if (mFormat == floatSample && (wavpackMode & MODE_FLOAT) != MODE_FLOAT) {
190 floatBuffer.reinit(bufferSize);
191 }
192
193 do {
194 samplesRead = WavpackUnpackSamples(mWavPackContext, wavpackBuffer.get(), SAMPLES_TO_READ);
195
196 if (mFormat == int16Sample) {
197 if (mBytesPerSample == 1)
198 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
199 int16Buffer[c] = static_cast<int16_t>(wavpackBuffer[c] * 256);
200 else
201 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
202 int16Buffer[c] = static_cast<int16_t>(wavpackBuffer[c]);
203
204 unsigned chn = 0;
205 ImportUtils::ForEachChannel(*trackList, [&](auto& channel)
206 {
207 channel.AppendBuffer(
208 reinterpret_cast<constSamplePtr>(int16Buffer.get() + chn),
209 mFormat,
210 samplesRead,
212 mFormat
213 );
214 ++chn;
215 });
216 } else if (mFormat == int24Sample || (wavpackMode & MODE_FLOAT) == MODE_FLOAT) {
217 unsigned chn = 0;
218 ImportUtils::ForEachChannel(*trackList, [&](auto& channel)
219 {
220 channel.AppendBuffer(
221 reinterpret_cast<constSamplePtr>(wavpackBuffer.get() + chn),
222 mFormat,
223 samplesRead,
225 mFormat
226 );
227 ++chn;
228 });
229 } else {
230 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
231 floatBuffer[c] = static_cast<float>(wavpackBuffer[c] / static_cast<double>(std::numeric_limits<int32_t>::max()));
232
233 unsigned chn = 0;
234 ImportUtils::ForEachChannel(*trackList, [&](auto& channel)
235 {
236 channel.AppendBuffer(
237 reinterpret_cast<constSamplePtr>(floatBuffer.get() + chn),
238 mFormat,
239 samplesRead,
241 mFormat
242 );
243 ++chn;
244 });
245 }
246
247 totalSamplesRead += samplesRead;
248
249 progressListener.OnImportProgress(WavpackGetProgress(mWavPackContext));
250 } while (!IsCancelled() && !IsStopped() && samplesRead != 0);
251 }
252
253 if (WavpackGetNumErrors(mWavPackContext))
255 XO( "Encountered %d errors decoding WavPack file!" ).Format( WavpackGetNumErrors(mWavPackContext) ));
256
257 if(IsCancelled())
258 {
260 return;
261 }
262
263 if (totalSamplesRead < mNumSamples && !IsStopped())
264 {
266 return;
267 }
268
269 ImportUtils::FinalizeImport(outTracks, trackList);
270
271 if (wavpackMode & MODE_VALID_TAG) {
272 bool apeTag = wavpackMode & MODE_APETAG;
273 int numItems = WavpackGetNumTagItems(mWavPackContext);
274
275 if (numItems > 0) {
276 tags->Clear();
277 for (int i = 0; i < numItems; i++) {
278 int itemLen = 0, valueLen = 0;
279 wxString value, name;
280
281 // Get the actual length of the item key at this index i
282 itemLen = WavpackGetTagItemIndexed(mWavPackContext, i, NULL, 0);
283 std::string item (itemLen + 1, '\0');
284 WavpackGetTagItemIndexed(mWavPackContext, i, item.data(), itemLen + 1);
285 item.resize(itemLen); // remove terminating NULL from std::string
287
288 // Get the actual length of the value for this item key
289 valueLen = WavpackGetTagItem(mWavPackContext, item.data(), NULL, 0);
290 std::string itemValue (valueLen + 1, '\0');
291 WavpackGetTagItem(mWavPackContext, item.data(), itemValue.data(), valueLen + 1);
292 itemValue.resize(valueLen); // remove terminating NULL from std::string
293
294 if (apeTag) {
295 for (int j = 0; j < valueLen; j++) {
296 // APEv2 text tags can have multiple NULL separated string values
297 if (!itemValue[j]) {
298 itemValue[j] = '\n';
299 }
300 }
301 }
302 value = audacity::ToWXString(itemValue);
303
304 if (name.Upper() == wxT("DATE") && !tags->HasTag(TAG_YEAR)) {
305 long val;
306 if (value.length() == 4 && value.ToLong(&val)) {
307 name = TAG_YEAR;
308 }
309 }
310
311 tags->SetTag(name, value);
312 }
313 }
314 }
315
316 progressListener.OnImportResult(IsStopped()
319}
320
322{
323 return 1;
324}
325
327{
328 static TranslatableStrings empty;
329 return empty;
330}
331
332void WavPackImportFileHandle::SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use))
333{
334}
335
337{
338 WavpackCloseFile(mWavPackContext);
339}
wxT("CloseDown"))
Declare functions to perform UTF-8 to std::wstring conversions.
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
The interface that all file import "plugins" (if you want to call them that) must implement....
std::vector< std::shared_ptr< TrackList > > TrackHolders
Definition: ImportRaw.h:24
static const auto exts
#define DESC
static Importer::RegisteredImportPlugin registered
wxString FilePath
Definition: Project.h:21
sampleFormat
The ordering of these values with operator < agrees with the order of increasing bit width.
Definition: SampleFormat.h:30
const char * constSamplePtr
Definition: SampleFormat.h:56
#define TAG_YEAR
Definition: Tags.h:62
std::vector< TranslatableString > TranslatableStrings
This simplifies arrays of arrays, each array separately allocated with NEW[] But it might be better t...
Definition: MemoryX.h:27
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Abstract base class used in importing a file.
bool IsStopped() const noexcept
bool IsCancelled() const noexcept
unsigned long long ByteCount
Definition: ImportPlugin.h:114
Base class for FlacImportPlugin, LOFImportPlugin, MP3ImportPlugin, OggImportPlugin and PCMImportPlugi...
Definition: ImportPlugin.h:67
Interface used to report on import state and progress.
virtual void OnImportResult(ImportResult result)=0
Used to report on import result for file handle passed as argument to OnImportFileOpened.
virtual void OnImportProgress(double progress)=0
static void ShowMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Import Project"))
Definition: ImportUtils.cpp:43
static TrackListHolder NewWaveTrack(WaveTrackFactory &trackFactory, unsigned nChannels, sampleFormat effectiveFormat, double rate)
Definition: ImportUtils.cpp:35
static void ForEachChannel(TrackList &trackList, const std::function< void(WaveChannel &)> &op)
Iterates over channels in each wave track from the list.
Definition: ImportUtils.cpp:66
static void FinalizeImport(TrackHolders &outTracks, const std::vector< TrackListHolder > &importedStreams)
Flushes the given channels and moves them to outTracks.
Definition: ImportUtils.cpp:49
ID3 Tags (for MP3)
Definition: Tags.h:73
void Clear()
Definition: Tags.cpp:298
bool HasTag(const wxString &name) const
Definition: Tags.cpp:397
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:431
Holds a msgid for the translation catalog; may also bind format arguments.
An ImportFileHandle for WavPack data.
TranslatableString GetFileDescription() override
void SetStreamUsage(wxInt32 StreamID, bool Use) override
WavpackContext * mWavPackContext
ByteCount GetFileUncompressedBytes() override
wxInt32 GetStreamCount() override
WavPackImportFileHandle(const FilePath &filename, WavpackContext *wavpackContext)
void Import(ImportProgressListener &progressListener, WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override
const TranslatableStrings & GetStreamInfo() override
An ImportPlugin for WavPack data.
std::unique_ptr< ImportFileHandle > Open(const FilePath &Filename, AudacityProject *) override
TranslatableString GetPluginFormatDescription() override
wxString GetPluginStringID() override
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:1166
A Track that contains audio waveform data.
Definition: WaveTrack.h:220
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
wxString ToWXString(const std::string &str)