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 tracks = trackFactory->CreateMany(mNumChannels, mFormat, mSampleRate);
172
173
174 /* The number of samples to read in each loop */
175 const size_t SAMPLES_TO_READ = (*tracks->Any<WaveTrack>().begin())->GetMaxBlockSize();
176 uint32_t totalSamplesRead = 0;
177
178 {
179 const uint32_t bufferSize = mNumChannels * SAMPLES_TO_READ;
180 ArrayOf<int32_t> wavpackBuffer{ bufferSize };
181 ArrayOf<int16_t> int16Buffer;
182 ArrayOf<float> floatBuffer;
183 uint32_t samplesRead = 0;
184
185 if (mFormat == int16Sample) {
186 int16Buffer.reinit(bufferSize);
187 } else if (mFormat == floatSample && (wavpackMode & MODE_FLOAT) != MODE_FLOAT) {
188 floatBuffer.reinit(bufferSize);
189 }
190
191 do {
192 samplesRead = WavpackUnpackSamples(mWavPackContext, wavpackBuffer.get(), SAMPLES_TO_READ);
193
194 if (mFormat == int16Sample) {
195 if (mBytesPerSample == 1)
196 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
197 int16Buffer[c] = static_cast<int16_t>(wavpackBuffer[c] * 256);
198 else
199 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
200 int16Buffer[c] = static_cast<int16_t>(wavpackBuffer[c]);
201
202 unsigned chn = 0;
203 ImportUtils::ForEachChannel(*tracks, [&](auto& channel)
204 {
205 channel.AppendBuffer(
206 reinterpret_cast<constSamplePtr>(int16Buffer.get() + chn),
207 mFormat,
208 samplesRead,
210 mFormat
211 );
212 ++chn;
213 });
214 } else if (mFormat == int24Sample || (wavpackMode & MODE_FLOAT) == MODE_FLOAT) {
215 unsigned chn = 0;
216 ImportUtils::ForEachChannel(*tracks, [&](auto& channel)
217 {
218 channel.AppendBuffer(
219 reinterpret_cast<constSamplePtr>(wavpackBuffer.get() + chn),
220 mFormat,
221 samplesRead,
223 mFormat
224 );
225 ++chn;
226 });
227 } else {
228 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
229 floatBuffer[c] = static_cast<float>(wavpackBuffer[c] / static_cast<double>(std::numeric_limits<int32_t>::max()));
230
231 unsigned chn = 0;
232 ImportUtils::ForEachChannel(*tracks, [&](auto& channel)
233 {
234 channel.AppendBuffer(
235 reinterpret_cast<constSamplePtr>(floatBuffer.get() + chn),
236 mFormat,
237 samplesRead,
239 mFormat
240 );
241 ++chn;
242 });
243 }
244
245 totalSamplesRead += samplesRead;
246
247 progressListener.OnImportProgress(WavpackGetProgress(mWavPackContext));
248 } while (!IsCancelled() && !IsStopped() && samplesRead != 0);
249 }
250
251 if (WavpackGetNumErrors(mWavPackContext))
253 XO( "Encountered %d errors decoding WavPack file!" ).Format( WavpackGetNumErrors(mWavPackContext) ));
254
255 if(IsCancelled())
256 {
258 return;
259 }
260
261 if (totalSamplesRead < mNumSamples && !IsStopped())
262 {
264 return;
265 }
266
267
268 ImportUtils::FinalizeImport(outTracks, std::move(*tracks));
269
270 if (wavpackMode & MODE_VALID_TAG) {
271 bool apeTag = wavpackMode & MODE_APETAG;
272 int numItems = WavpackGetNumTagItems(mWavPackContext);
273
274 if (numItems > 0) {
275 tags->Clear();
276 for (int i = 0; i < numItems; i++) {
277 int itemLen = 0, valueLen = 0;
278 wxString value, name;
279
280 // Get the actual length of the item key at this index i
281 itemLen = WavpackGetTagItemIndexed(mWavPackContext, i, NULL, 0);
282 std::string item (itemLen + 1, '\0');
283 WavpackGetTagItemIndexed(mWavPackContext, i, item.data(), itemLen + 1);
284 item.resize(itemLen); // remove terminating NULL from std::string
286
287 // Get the actual length of the value for this item key
288 valueLen = WavpackGetTagItem(mWavPackContext, item.data(), NULL, 0);
289 std::string itemValue (valueLen + 1, '\0');
290 WavpackGetTagItem(mWavPackContext, item.data(), itemValue.data(), valueLen + 1);
291 itemValue.resize(valueLen); // remove terminating NULL from std::string
292
293 if (apeTag) {
294 for (int j = 0; j < valueLen; j++) {
295 // APEv2 text tags can have multiple NULL separated string values
296 if (!itemValue[j]) {
297 itemValue[j] = '\n';
298 }
299 }
300 }
301 value = audacity::ToWXString(itemValue);
302
303 if (name.Upper() == wxT("DATE") && !tags->HasTag(TAG_YEAR)) {
304 long val;
305 if (value.length() == 4 && value.ToLong(&val)) {
306 name = TAG_YEAR;
307 }
308 }
309
310 tags->SetTag(name, value);
311 }
312 }
313 }
314
315 progressListener.OnImportResult(IsStopped()
318}
319
321{
322 return 1;
323}
324
326{
327 static TranslatableStrings empty;
328 return empty;
329}
330
331void WavPackImportFileHandle::SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use))
332{
333}
334
336{
337 WavpackCloseFile(mWavPackContext);
338}
wxT("CloseDown"))
Declare functions to perform UTF-8 to std::wstring conversions.
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
wxString name
Definition: TagsEditor.cpp:166
const auto tracks
std::vector< TranslatableString > TranslatableStrings
This simplifies arrays of arrays, each array separately allocated with NEW[] But it might be better t...
Definition: MemoryX.h:29
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:59
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 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:871
TrackListHolder CreateMany(size_t nChannels)
Creates tracks with project's default rate and format and the given number of channels.
Definition: WaveTrack.cpp:423
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
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