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 "Prefs.h"
32#include "Tags.h"
33#include "WaveTrack.h"
34#include "ProgressDialog.h"
35#include "AudacityMessageBox.h"
36#include "CodeConversions.h"
37
38#define DESC XO("WavPack files")
39
40static const auto exts = {
41 wxT("wv")
42};
43
45{
46public:
49
50 wxString GetPluginStringID() override;
52 std::unique_ptr<ImportFileHandle> Open(
53 const FilePath &Filename, AudacityProject*) override;
54};
55
56using NewChannelGroup = std::vector< std::shared_ptr<WaveTrack> >;
57
59{
60public:
61 WavPackImportFileHandle(const FilePath &filename, WavpackContext* wavpackContext);
63
66 ProgressResult Import(WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override;
67 wxInt32 GetStreamCount() override;
68 const TranslatableStrings &GetStreamInfo() override;
69 void SetStreamUsage(wxInt32 StreamID, bool Use) override;
70
71private:
72 WavpackContext *mWavPackContext;
74 uint32_t mSampleRate;
77 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: ImportFileHandle(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{
162 const int wavpackMode = WavpackGetMode(mWavPackContext);
163
164 outTracks.clear();
165
167
168 mChannels.resize(mNumChannels);
169
170 {
171 auto iter = mChannels.begin();
172 for (size_t c = 0; c < mNumChannels; ++iter, ++c)
173 *iter = NewWaveTrack(*trackFactory, mFormat, mSampleRate);
174 }
175
176 /* The number of samples to read in each loop */
177 const size_t SAMPLES_TO_READ = mChannels.begin()->get()->GetMaxBlockSize();
178 auto updateResult = ProgressResult::Success;
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 for (unsigned channel = 0; channel < mNumChannels; channel++) {
206 mChannels[channel]->Append(
207 reinterpret_cast<constSamplePtr>(int16Buffer.get() + channel),
208 mFormat, samplesRead, mNumChannels, mFormat);
209 }
210
211 } else if (mFormat == int24Sample || (wavpackMode & MODE_FLOAT) == MODE_FLOAT) {
212 for (unsigned channel = 0; channel < mNumChannels; channel++) {
213 mChannels[channel]->Append(
214 reinterpret_cast<constSamplePtr>(wavpackBuffer.get() + channel),
215 mFormat, samplesRead, mNumChannels, mFormat);
216 }
217
218 } else {
219 for (int64_t c = 0; c < samplesRead * mNumChannels; c++)
220 floatBuffer[c] = static_cast<float>(wavpackBuffer[c] / static_cast<double>(std::numeric_limits<int32_t>::max()));
221
222 for (unsigned channel = 0; channel < mNumChannels; channel++) {
223 mChannels[channel]->Append(
224 reinterpret_cast<constSamplePtr>(floatBuffer.get() + channel),
225 mFormat, samplesRead, mNumChannels, mFormat);
226 }
227 }
228
229 totalSamplesRead += samplesRead;
230 updateResult = mProgress->Update(WavpackGetProgress(mWavPackContext), 1.0);
231 } while (updateResult == ProgressResult::Success && samplesRead != 0);
232 }
233
234 if (WavpackGetNumErrors(mWavPackContext))
235 AudacityMessageBox( XO( "Encountered %d errors decoding WavPack file!" ).Format( WavpackGetNumErrors(mWavPackContext) ),
236 XO( "WavPack Importer" ), wxOK | wxICON_EXCLAMATION | wxCENTRE);
237
238 if (updateResult != ProgressResult::Stopped && updateResult != ProgressResult::Cancelled
239 && totalSamplesRead < mNumSamples)
240 updateResult = ProgressResult::Failed;
241
242 if (updateResult == ProgressResult::Failed || updateResult == ProgressResult::Cancelled)
243 return updateResult;
244
245 for (const auto &channel : mChannels)
246 channel->Flush();
247
248 if (!mChannels.empty())
249 outTracks.push_back(std::move(mChannels));
250
251 if (wavpackMode & MODE_VALID_TAG) {
252 bool apeTag = wavpackMode & MODE_APETAG;
253 int numItems = WavpackGetNumTagItems(mWavPackContext);
254
255 if (numItems > 0) {
256 tags->Clear();
257 for (int i = 0; i < numItems; i++) {
258 int itemLen = 0, valueLen = 0;
259 wxString value, name;
260
261 // Get the actual length of the item key at this index i
262 itemLen = WavpackGetTagItemIndexed(mWavPackContext, i, NULL, 0);
263 std::string item (itemLen + 1, '\0');
264 WavpackGetTagItemIndexed(mWavPackContext, i, item.data(), itemLen + 1);
265 item.resize(itemLen); // remove terminating NULL from std::string
267
268 // Get the actual length of the value for this item key
269 valueLen = WavpackGetTagItem(mWavPackContext, item.data(), NULL, 0);
270 std::string itemValue (valueLen + 1, '\0');
271 WavpackGetTagItem(mWavPackContext, item.data(), itemValue.data(), valueLen + 1);
272 itemValue.resize(valueLen); // remove terminating NULL from std::string
273
274 if (apeTag) {
275 for (int j = 0; j < valueLen; j++) {
276 // APEv2 text tags can have multiple NULL separated string values
277 if (!itemValue[j]) {
278 itemValue[j] = '\n';
279 }
280 }
281 }
282 value = audacity::ToWXString(itemValue);
283
284 if (name.Upper() == wxT("DATE") && !tags->HasTag(TAG_YEAR)) {
285 long val;
286 if (value.length() == 4 && value.ToLong(&val)) {
287 name = TAG_YEAR;
288 }
289 }
290
291 tags->SetTag(name, value);
292 }
293 }
294 }
295
296 return updateResult;
297}
298
300{
301 return 1;
302}
303
305{
306 static TranslatableStrings empty;
307 return empty;
308}
309
310void WavPackImportFileHandle::SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use))
311{
312}
313
315{
316 WavpackCloseFile(mWavPackContext);
317}
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Declare functions to perform UTF-8 to std::wstring conversions.
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
std::vector< std::shared_ptr< WaveTrack > > NewChannelGroup
Definition: Import.cpp:59
std::vector< std::vector< std::shared_ptr< WaveTrack > > > TrackHolders
Definition: Import.h:39
The interface that all file import "plugins" (if you want to call them that) must implement....
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.
An ImportFileHandle for data.
Definition: ImportPlugin.h:112
unsigned long long ByteCount
Definition: ImportPlugin.h:132
std::unique_ptr< ProgressDialog > mProgress
Definition: ImportPlugin.h:164
std::shared_ptr< WaveTrack > NewWaveTrack(WaveTrackFactory &trackFactory, sampleFormat effectiveFormat, double rate)
Build a wave track with appropriate format, which will not be narrower than the specified one.
Base class for FlacImportPlugin, LOFImportPlugin, MP3ImportPlugin, OggImportPlugin and PCMImportPlugi...
Definition: ImportPlugin.h:68
ID3 Tags (for MP3)
Definition: Tags.h:73
void Clear()
Definition: Tags.cpp:308
bool HasTag(const wxString &name) const
Definition: Tags.cpp:407
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:441
Holds a msgid for the translation catalog; may also bind format arguments.
An ImportFileHandle for WavPack data.
TranslatableString GetFileDescription() override
ProgressResult Import(WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override
ProgressResult mUpdateResult
void SetStreamUsage(wxInt32 StreamID, bool Use) override
WavpackContext * mWavPackContext
ByteCount GetFileUncompressedBytes() override
wxInt32 GetStreamCount() override
WavPackImportFileHandle(const FilePath &filename, WavpackContext *wavpackContext)
NewChannelGroup mChannels
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:565
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
ProgressResult
Definition: BasicUI.h:147
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)