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,
67 std::optional<LibFileFormats::AcidizerTags>& outAcidTags) override;
68
69 wxInt32 GetStreamCount() override;
70 const TranslatableStrings &GetStreamInfo() override;
71 void SetStreamUsage(wxInt32 StreamID, bool Use) override;
72
73private:
74 WavpackContext *mWavPackContext;
76 uint32_t mSampleRate;
79 int64_t mNumSamples;
81};
82
83// ============================================================================
84// WavPackImportPlugin
85// ============================================================================
86
89{
90}
91
93{
94}
95
97{
98 return wxT("libwavpack");
99}
100
102{
103 return DESC;
104}
105
106std::unique_ptr<ImportFileHandle> WavPackImportPlugin::Open(const FilePath &filename, AudacityProject*)
107{
108 char errMessage[100]; // To hold possible error message
109 int flags = OPEN_WVC | OPEN_FILE_UTF8 | OPEN_TAGS | OPEN_DSD_AS_PCM | OPEN_NORMALIZE;
110 WavpackContext *wavpackContext = WavpackOpenFileInput(filename, errMessage, flags, 0);
111
112 if (!wavpackContext) {
113 // Some error occured(e.g. File not found or is invalid)
114 wxLogDebug("WavpackOpenFileInput() failed on file %s, error = %s", filename, errMessage);
115 return nullptr;
116 }
117
118 auto handle = std::make_unique<WavPackImportFileHandle>(filename, wavpackContext);
119
120 return std::move(handle);
121}
122
124 std::make_unique< WavPackImportPlugin >()
125};
126
127// ============================================================================
128// WavPackImportFileHandle
129// ============================================================================
130
132 WavpackContext *wavpackContext)
133: ImportFileHandleEx(filename),
134 mWavPackContext(wavpackContext),
135 mNumChannels(WavpackGetNumChannels(mWavPackContext)),
136 mSampleRate(WavpackGetSampleRate(mWavPackContext)),
137 mBitsPerSample(WavpackGetBitsPerSample(mWavPackContext)),
138 mBytesPerSample(WavpackGetBytesPerSample(mWavPackContext)),
139 mNumSamples(WavpackGetNumSamples64(mWavPackContext))
140{
141 if (mBitsPerSample <= 16) {
143 } else if (mBitsPerSample <= 24) {
145 } else {
147 }
148}
149
151{
152 return DESC;
153}
154
156{
157 return 0;
158}
159
161 ImportProgressListener& progressListener, WaveTrackFactory* trackFactory,
162 TrackHolders& outTracks, Tags* tags,
163 std::optional<LibFileFormats::AcidizerTags>&)
164{
165 BeginImport();
166
167 const int wavpackMode = WavpackGetMode(mWavPackContext);
168
169 outTracks.clear();
170
171 auto track = ImportUtils::NewWaveTrack(
172 *trackFactory,
174 mFormat,
176
177 /* The number of samples to read in each loop */
178 const size_t SAMPLES_TO_READ = track->GetMaxBlockSize();
179 uint32_t totalSamplesRead = 0;
180
181 {
182 const uint32_t bufferSize = mNumChannels * SAMPLES_TO_READ;
183 ArrayOf<int32_t> wavpackBuffer{ bufferSize };
184 ArrayOf<int16_t> int16Buffer;
185 ArrayOf<float> floatBuffer;
186 uint32_t samplesRead = 0;
187
188 if (mFormat == int16Sample) {
189 int16Buffer.reinit(bufferSize);
190 } else if (mFormat == floatSample && (wavpackMode & MODE_FLOAT) != MODE_FLOAT) {
191 floatBuffer.reinit(bufferSize);
192 }
193
194 do {
195 samplesRead = WavpackUnpackSamples(mWavPackContext, wavpackBuffer.get(), SAMPLES_TO_READ);
196
197 if (mFormat == int16Sample) {
198 if (mBytesPerSample == 1)
199 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
200 int16Buffer[c] = static_cast<int16_t>(wavpackBuffer[c] * 256);
201 else
202 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
203 int16Buffer[c] = static_cast<int16_t>(wavpackBuffer[c]);
204
205 unsigned chn = 0;
206 ImportUtils::ForEachChannel(*track, [&](auto& channel)
207 {
208 channel.AppendBuffer(
209 reinterpret_cast<constSamplePtr>(int16Buffer.get() + chn),
210 mFormat,
211 samplesRead,
213 mFormat
214 );
215 ++chn;
216 });
217 } else if (mFormat == int24Sample || (wavpackMode & MODE_FLOAT) == MODE_FLOAT) {
218 unsigned chn = 0;
219 ImportUtils::ForEachChannel(*track, [&](auto& channel)
220 {
221 channel.AppendBuffer(
222 reinterpret_cast<constSamplePtr>(wavpackBuffer.get() + chn),
223 mFormat,
224 samplesRead,
226 mFormat
227 );
228 ++chn;
229 });
230 } else {
231 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
232 floatBuffer[c] = static_cast<float>(wavpackBuffer[c] / static_cast<double>(std::numeric_limits<int32_t>::max()));
233
234 unsigned chn = 0;
235 ImportUtils::ForEachChannel(*track, [&](auto& channel)
236 {
237 channel.AppendBuffer(
238 reinterpret_cast<constSamplePtr>(floatBuffer.get() + chn),
239 mFormat,
240 samplesRead,
242 mFormat
243 );
244 ++chn;
245 });
246 }
247
248 totalSamplesRead += samplesRead;
249
250 progressListener.OnImportProgress(WavpackGetProgress(mWavPackContext));
251 } while (!IsCancelled() && !IsStopped() && samplesRead != 0);
252 }
253
254 if (WavpackGetNumErrors(mWavPackContext))
256 XO( "Encountered %d errors decoding WavPack file!" ).Format( WavpackGetNumErrors(mWavPackContext) ));
257
258 if(IsCancelled())
259 {
261 return;
262 }
263
264 if (totalSamplesRead < mNumSamples && !IsStopped())
265 {
267 return;
268 }
269
270 ImportUtils::FinalizeImport(outTracks, *track);
271
272 if (wavpackMode & MODE_VALID_TAG) {
273 bool apeTag = wavpackMode & MODE_APETAG;
274 int numItems = WavpackGetNumTagItems(mWavPackContext);
275
276 if (numItems > 0) {
277 tags->Clear();
278 for (int i = 0; i < numItems; i++) {
279 int itemLen = 0, valueLen = 0;
280 wxString value, name;
281
282 // Get the actual length of the item key at this index i
283 itemLen = WavpackGetTagItemIndexed(mWavPackContext, i, NULL, 0);
284 std::string item (itemLen + 1, '\0');
285 WavpackGetTagItemIndexed(mWavPackContext, i, item.data(), itemLen + 1);
286 item.resize(itemLen); // remove terminating NULL from std::string
288
289 // Get the actual length of the value for this item key
290 valueLen = WavpackGetTagItem(mWavPackContext, item.data(), NULL, 0);
291 std::string itemValue (valueLen + 1, '\0');
292 WavpackGetTagItem(mWavPackContext, item.data(), itemValue.data(), valueLen + 1);
293 itemValue.resize(valueLen); // remove terminating NULL from std::string
294
295 if (apeTag) {
296 for (int j = 0; j < valueLen; j++) {
297 // APEv2 text tags can have multiple NULL separated string values
298 if (!itemValue[j]) {
299 itemValue[j] = '\n';
300 }
301 }
302 }
303 value = audacity::ToWXString(itemValue);
304
305 if (name.Upper() == wxT("DATE") && !tags->HasTag(TAG_YEAR)) {
306 long val;
307 if (value.length() == 4 && value.ToLong(&val)) {
308 name = TAG_YEAR;
309 }
310 }
311
312 tags->SetTag(name, value);
313 }
314 }
315 }
316
317 progressListener.OnImportResult(IsStopped()
320}
321
323{
324 return 1;
325}
326
328{
329 static TranslatableStrings empty;
330 return empty;
331}
332
333void WavPackImportFileHandle::SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use))
334{
335}
336
338{
339 WavpackCloseFile(mWavPackContext);
340}
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< Track > > 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:58
#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:28
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:58
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 std::shared_ptr< WaveTrack > 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:73
static void FinalizeImport(TrackHolders &outTracks, const std::vector< std::shared_ptr< WaveTrack > > &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:293
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 Import(ImportProgressListener &progressListener, WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags, std::optional< LibFileFormats::AcidizerTags > &outAcidTags) override
void SetStreamUsage(wxInt32 StreamID, bool Use) override
WavpackContext * mWavPackContext
ByteCount GetFileUncompressedBytes() override
wxInt32 GetStreamCount() override
WavPackImportFileHandle(const FilePath &filename, WavpackContext *wavpackContext)
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:870
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
wxString ToWXString(const std::string &str)
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101