Audacity  2.2.2
Classes | Enumerations | Functions
ImportRaw.cpp File Reference

Functions for guessing audio type and attempting to read from unknown sample audio data. Implements ImportRawDialog. More...

#include "../Audacity.h"
#include "ImportRaw.h"
#include "Import.h"
#include "../DirManager.h"
#include "../FileException.h"
#include "../FileFormats.h"
#include "../Internat.h"
#include "../Prefs.h"
#include "../ShuttleGui.h"
#include "../UserException.h"
#include "../WaveTrack.h"
#include "../prefs/QualityPrefs.h"
#include <cmath>
#include <cstdio>
#include <stdint.h>
#include <vector>
#include <wx/crt.h>
#include <wx/defs.h>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/intl.h>
#include <wx/panel.h>
#include <wx/progdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/timer.h>
#include "MultiFormatReader.h"
#include "FormatClassifier.h"
#include "sndfile.h"

Go to the source code of this file.

Classes

class  ImportRawDialog
 ImportRawDialog prompts you with options such as endianness and sample size to help you importing data of an unknown format. More...
 

Enumerations

enum  { ChoiceID = 9000, PlayID }
 

Functions

void ImportRaw (wxWindow *parent, const wxString &fileName, TrackFactory *trackFactory, TrackHolders &outTracks)
 

Detailed Description

Functions for guessing audio type and attempting to read from unknown sample audio data. Implements ImportRawDialog.

Definition in file ImportRaw.cpp.

Enumeration Type Documentation

anonymous enum
Enumerator
ChoiceID 
PlayID 

Definition at line 307 of file ImportRaw.cpp.

307  {
308  ChoiceID = 9000,
309  PlayID
310 };

Function Documentation

void ImportRaw ( wxWindow *  parent,
const wxString &  fileName,
TrackFactory trackFactory,
TrackHolders outTracks 
)

Definition at line 101 of file ImportRaw.cpp.

References _(), Cancelled, Failed, floatSample, format, FormatClassifier::GetResultFormatLibSndfile(), int16Sample, Track::LeftChannel, limitSampleBufferSize(), ImportRawDialog::mChannels, ImportRawDialog::mEncoding, ImportRawDialog::mOffset, Track::MonoChannel, ImportRawDialog::mPercent, ImportRawDialog::mRate, TrackFactory::NewWaveTrack(), FileException::Open, SampleBuffer::ptr(), FileException::Read, Track::RightChannel, QualityPrefs::SampleFormatChoice(), sf_subtype_more_than_16_bits(), Success, and ProgressDialog::Update().

Referenced by AudacityProject::OnImportRaw().

103 {
104  outTracks.clear();
105  int encoding = 0; // Guess Format
107  sf_count_t offset = 0;
108  double rate = 44100.0;
109  double percent = 100.0;
110  TrackHolders channels;
111  auto updateResult = ProgressResult::Success;
112 
113  {
114  SF_INFO sndInfo;
115  int result;
116 
117  unsigned numChannels = 0;
118 
119  try {
120  // Yes, FormatClassifier currently handles filenames in UTF8 format only, that's
121  // a TODO ...
122  FormatClassifier theClassifier(fileName.utf8_str());
123  encoding = theClassifier.GetResultFormatLibSndfile();
124  numChannels = theClassifier.GetResultChannels();
125  offset = 0;
126  } catch (...) {
127  // Something went wrong in FormatClassifier, use defaults instead.
128  encoding = 0;
129  }
130 
131  if (encoding <= 0) {
132  // Unable to guess. Use mono, 16-bit samples with CPU endianness
133  // as the default.
134  encoding = SF_FORMAT_RAW | SF_ENDIAN_CPU | SF_FORMAT_PCM_16;
135  numChannels = 1;
136  offset = 0;
137  }
138 
139  numChannels = std::max(1u, numChannels);
140  ImportRawDialog dlog(parent, encoding, numChannels, (int)offset, rate);
141  dlog.ShowModal();
142  if (!dlog.GetReturnCode())
143  return;
144 
145  encoding = dlog.mEncoding;
146  numChannels = dlog.mChannels;
147  rate = dlog.mRate;
148  offset = (sf_count_t)dlog.mOffset;
149  percent = dlog.mPercent;
150 
151  memset(&sndInfo, 0, sizeof(SF_INFO));
152  sndInfo.samplerate = (int)rate;
153  sndInfo.channels = (int)numChannels;
154  sndInfo.format = encoding | SF_FORMAT_RAW;
155 
156  wxFile f; // will be closed when it goes out of scope
157  SFFile sndFile;
158 
159  if (f.Open(fileName)) {
160  // Even though there is an sf_open() that takes a filename, use the one that
161  // takes a file descriptor since wxWidgets can open a file with a Unicode name and
162  // libsndfile can't (under Windows).
163  sndFile.reset(SFCall<SNDFILE*>(sf_open_fd, f.fd(), SFM_READ, &sndInfo, FALSE));
164  }
165 
166  if (!sndFile){
167  char str[1000];
168  sf_error_str((SNDFILE *)NULL, str, 1000);
169  wxPrintf("%s\n", str);
170 
171  throw FileException{ FileException::Cause::Open, fileName };
172  }
173 
174  result = sf_command(sndFile.get(), SFC_SET_RAW_START_OFFSET, &offset, sizeof(offset));
175  if (result != 0) {
176  char str[1000];
177  sf_error_str(sndFile.get(), str, 1000);
178  wxPrintf("%s\n", str);
179 
180  throw FileException{ FileException::Cause::Read, fileName };
181  }
182 
183  SFCall<sf_count_t>(sf_seek, sndFile.get(), 0, SEEK_SET);
184 
185  auto totalFrames =
186  // fraction of a sf_count_t value
187  (sampleCount)(sndInfo.frames * percent / 100.0);
188 
189  //
190  // Sample format:
191  //
192  // In general, go with the user's preferences. However, if
193  // the file is higher-quality, go with a format which preserves
194  // the quality of the original file.
195  //
196 
198 
199  if (format != floatSample &&
201  format = floatSample;
202 
203  channels.resize(numChannels);
204 
205  auto iter = channels.begin();
206  for (decltype(numChannels) c = 0; c < numChannels; ++iter, ++c) {
207  const auto channel =
208  (*iter = trackFactory->NewWaveTrack(format, rate)).get();
209 
210  if (numChannels > 1)
211  switch (c) {
212  case 0:
213  channel->SetChannel(Track::LeftChannel);
214  break;
215  case 1:
216  channel->SetChannel(Track::RightChannel);
217  break;
218  default:
219  channel->SetChannel(Track::MonoChannel);
220  }
221  }
222 
223  const auto firstChannel = channels.begin()->get();
224  if (numChannels == 2) {
225  firstChannel->SetLinked(true);
226  }
227 
228  auto maxBlockSize = firstChannel->GetMaxBlockSize();
229 
230  SampleBuffer srcbuffer(maxBlockSize * numChannels, format);
231  SampleBuffer buffer(maxBlockSize, format);
232 
233  decltype(totalFrames) framescompleted = 0;
234  if (totalFrames < 0) {
235  wxASSERT(false);
236  totalFrames = 0;
237  }
238 
239  wxString msg;
240 
241  msg.Printf(_("Importing %s"), wxFileName::FileName(fileName).GetFullName());
242 
243  /* i18n-hint: 'Raw' means 'unprocessed' here and should usually be tanslated.*/
244  ProgressDialog progress(_("Import Raw"), msg);
245 
246  size_t block;
247  do {
248  block =
249  limitSampleBufferSize( maxBlockSize, totalFrames - framescompleted );
250 
251  sf_count_t result;
252  if (format == int16Sample)
253  result = SFCall<sf_count_t>(sf_readf_short, sndFile.get(), (short *)srcbuffer.ptr(), block);
254  else
255  result = SFCall<sf_count_t>(sf_readf_float, sndFile.get(), (float *)srcbuffer.ptr(), block);
256 
257  if (result >= 0) {
258  block = result;
259  }
260  else {
261  // This is not supposed to happen, sndfile.h says result is always
262  // a count, not an invalid value for error
263  throw FileException{ FileException::Cause::Read, fileName };
264  }
265 
266  if (block) {
267  auto iter = channels.begin();
268  for(decltype(numChannels) c = 0; c < numChannels; ++iter, ++c) {
269  if (format==int16Sample) {
270  for(decltype(block) j=0; j<block; j++)
271  ((short *)buffer.ptr())[j] =
272  ((short *)srcbuffer.ptr())[numChannels*j+c];
273  }
274  else {
275  for(decltype(block) j=0; j<block; j++)
276  ((float *)buffer.ptr())[j] =
277  ((float *)srcbuffer.ptr())[numChannels*j+c];
278  }
279 
280  iter->get()->Append(buffer.ptr(), (format == int16Sample)?int16Sample:floatSample, block);
281  }
282  framescompleted += block;
283  }
284 
285  updateResult = progress.Update(
286  framescompleted.as_long_long(),
287  totalFrames.as_long_long()
288  );
289  if (updateResult != ProgressResult::Success)
290  break;
291 
292  } while (block > 0 && framescompleted < totalFrames);
293  }
294 
295  if (updateResult == ProgressResult::Failed || updateResult == ProgressResult::Cancelled)
296  throw UserException{};
297 
298  for (const auto &channel : channels)
299  channel->Flush();
300  outTracks.swap(channels);
301 }
ProgressDialog Class.
bool sf_subtype_more_than_16_bits(unsigned int format)
FormatClassifier classifies the sample format and endianness of raw audio files.
ImportRawDialog prompts you with options such as endianness and sample size to help you importing dat...
Definition: ImportRaw.cpp:62
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: Types.h:178
int format
Definition: ExportPCM.cpp:56
sampleFormat
Definition: Types.h:188
if(pTrack &&pTrack->GetDisplay()!=WaveTrack::Spectrum)
std::unique_ptr< WaveTrack > NewWaveTrack(sampleFormat format=(sampleFormat) 0, double rate=0)
Definition: WaveTrack.cpp:78
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
static sampleFormat SampleFormatChoice()
std::vector< std::unique_ptr< WaveTrack >> TrackHolders
Definition: ImportRaw.h:24