/********************************************************************** Audacity: A Digital Audio Editor ImportRaw.cpp Dominic Mazzoni *******************************************************************//** \file ImportRaw.cpp \brief Functions for guessing audio type and attempting to read from unknown sample audio data. Implements ImportRawDialog. *//****************************************************************//** \class ImportRawDialog \brief ImportRawDialog prompts you with options such as endianness and sample size to help you importing data of an unknown format. *//*******************************************************************/ #include "../Audacity.h" #include "ImportRaw.h" #include "Import.h" #include "RawAudioGuess.h" #include "../DirManager.h" #include "../FileFormats.h" #include "../Internat.h" #include "../Prefs.h" #include "../ShuttleGui.h" #include "../WaveTrack.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "sndfile.h" class ImportRawDialog:public wxDialog { public: ImportRawDialog(wxWindow * parent, int encoding, int channels, int offset, double rate); ~ImportRawDialog(); void OnOK(wxCommandEvent & event); void OnCancel(wxCommandEvent & event); void OnPlay(wxCommandEvent & event); void OnChoice(wxCommandEvent & event); // in and out int mEncoding; int mChannels; int mOffset; double mRate; double mPercent; private: wxButton *mOK; wxChoice *mEncodingChoice; wxChoice *mEndianChoice; wxChoice *mChannelChoice; wxTextCtrl *mOffsetText; wxTextCtrl *mPercentText; wxTextCtrl *mRateText; int mNumEncodings; int *mEncodingSubtype; DECLARE_EVENT_TABLE() }; int ImportRaw(wxWindow *parent, wxString fileName, TrackFactory *trackFactory, Track ***outTracks) { int encoding = 0; // Guess Format int numChannels = 0; sampleFormat format; sf_count_t offset = 0; int int_offset = 0; sampleCount totalFrames; double rate = 44100.0; double percent = 100.0; SNDFILE *sndFile = NULL; SF_INFO sndInfo; int result; encoding = RawAudioGuess(fileName, &int_offset, &numChannels); offset = (sf_count_t)int_offset; if (encoding <= 0) { // Unable to guess. Use mono, 16-bit samples with CPU endianness // as the default. encoding = SF_FORMAT_RAW | SF_ENDIAN_CPU | SF_FORMAT_PCM_16; numChannels = 1; offset = 0; } ImportRawDialog dlog(parent, encoding, numChannels, (int)offset, rate); dlog.ShowModal(); if (!dlog.GetReturnCode()) return false; encoding = dlog.mEncoding; numChannels = dlog.mChannels; rate = dlog.mRate; offset = (sf_count_t)dlog.mOffset; percent = dlog.mPercent; memset(&sndInfo, 0, sizeof(SF_INFO)); sndInfo.samplerate = (int)rate; sndInfo.channels = (int)numChannels; sndInfo.format = encoding | SF_FORMAT_RAW; wxFile f; // will be closed when it goes out of scope if (f.Open(fileName)) { // Even though there is an sf_open() that takes a filename, use the one that // takes a file descriptor since wxWidgets can open a file with a Unicode name and // libsndfile can't (under Windows). sndFile = sf_open_fd(f.fd(), SFM_READ, &sndInfo, FALSE); } if (!sndFile){ // TODO: Handle error char str[1000]; sf_error_str((SNDFILE *)NULL, str, 1000); printf("%s\n", str); return 0; } result = sf_command(sndFile, SFC_SET_RAW_START_OFFSET, &offset, sizeof(offset)); if (result != 0) { char str[1000]; sf_error_str(sndFile, str, 1000); printf("%s\n", str); } sf_seek(sndFile, 0, SEEK_SET); totalFrames = (sampleCount)(sndInfo.frames * percent / 100.0); // // Sample format: // // In general, go with the user's preferences. However, if // the file is higher-quality, go with a format which preserves // the quality of the original file. // format = (sampleFormat) gPrefs->Read(wxT("/SamplingRate/DefaultProjectSampleFormat"), floatSample); if (format != floatSample && sf_subtype_more_than_16_bits(encoding)) format = floatSample; WaveTrack **channels = new WaveTrack *[numChannels]; int c; for (c = 0; c < numChannels; c++) { channels[c] = trackFactory->NewWaveTrack(format, rate); if (numChannels > 1) switch (c) { case 0: channels[c]->SetChannel(Track::LeftChannel); break; case 1: channels[c]->SetChannel(Track::RightChannel); break; default: channels[c]->SetChannel(Track::MonoChannel); } } if (numChannels == 2) { channels[0]->SetLinked(true); } sampleCount maxBlockSize = channels[0]->GetMaxBlockSize(); int updateResult = eProgressSuccess; samplePtr srcbuffer = NewSamples(maxBlockSize * numChannels, format); samplePtr buffer = NewSamples(maxBlockSize, format); sampleCount framescompleted = 0; wxString msg; msg.Printf(_("Importing %s"), wxFileName::FileName(fileName).GetFullName().c_str()); ProgressDialog progress(_("Import Raw"), msg); long block; do { block = maxBlockSize; if (block + framescompleted > totalFrames) block = totalFrames - framescompleted; if (format == int16Sample) block = sf_readf_short(sndFile, (short *)srcbuffer, block); else block = sf_readf_float(sndFile, (float *)srcbuffer, block); if (block) { for(c=0; cAppend(buffer, format, block); } framescompleted += block; } updateResult = progress.Update((wxULongLong_t)framescompleted, (wxULongLong_t)totalFrames); if (updateResult != eProgressSuccess) break; } while (block > 0 && framescompleted < totalFrames); sf_close(sndFile); int res = updateResult; if (block < 0) res = eProgressFailed; if (res == eProgressFailed || res == eProgressCancelled) { for (c = 0; c < numChannels; c++) delete channels[c]; delete[] channels; // It's a shame we can't return proper error code return 0; } for (c = 0; c < numChannels; c++) channels[c]->Flush(); *outTracks = (Track **)channels; return numChannels; } // // ImportRawDialog // enum { ChoiceID = 9000, PlayID }; BEGIN_EVENT_TABLE(ImportRawDialog, wxDialog) EVT_BUTTON(wxID_OK, ImportRawDialog::OnOK) EVT_BUTTON(wxID_CANCEL, ImportRawDialog::OnCancel) EVT_BUTTON(PlayID, ImportRawDialog::OnPlay) EVT_CHOICE(ChoiceID, ImportRawDialog::OnChoice) END_EVENT_TABLE() ImportRawDialog::ImportRawDialog(wxWindow * parent, int encoding, int channels, int offset, double rate) : wxDialog(parent, wxID_ANY, _("Import Raw Data"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), mEncoding(encoding), mChannels(channels), mOffset(offset), mRate(rate) { ShuttleGui S(this, eIsCreating); wxArrayString encodings; wxArrayString endians; wxArrayString chans; int num; int selection; int endian; int i; num = sf_num_encodings(); mNumEncodings = 0; mEncodingSubtype = new int[num]; selection = 0; for (i=0; iSetLabel(_("&Import")); } S.EndVerticalLay(); Fit(); SetSizeHints(GetSize()); Centre(wxBOTH); } ImportRawDialog::~ImportRawDialog() { delete[] mEncodingSubtype; } void ImportRawDialog::OnOK(wxCommandEvent & WXUNUSED(event)) { long l; mEncoding = mEncodingSubtype[mEncodingChoice->GetSelection()]; mEncoding += (mEndianChoice->GetSelection() * 0x10000000); mChannels = mChannelChoice->GetSelection() + 1; mOffsetText->GetValue().ToLong(&l); mOffset = l; mPercentText->GetValue().ToDouble(&mPercent); mRateText->GetValue().ToDouble(&mRate); if (mChannels < 1 || mChannels > 16) mChannels = 1; if (mOffset < 0) mOffset = 0; if (mPercent < 0.0) mPercent = 0.0; if (mPercent > 100.0) mPercent = 100.0; if (mRate < 100.0) mRate = 100.0; if (mRate > 100000.0) mRate = 100000.0; EndModal(true); } void ImportRawDialog::OnCancel(wxCommandEvent & WXUNUSED(event)) { EndModal(false); } void ImportRawDialog::OnPlay(wxCommandEvent & WXUNUSED(event)) { } void ImportRawDialog::OnChoice(wxCommandEvent & WXUNUSED(event)) { SF_INFO info; memset(&info, 0, sizeof(SF_INFO)); mEncoding = mEncodingSubtype[mEncodingChoice->GetSelection()]; mEncoding += (mEndianChoice->GetSelection() * 0x10000000); info.format = mEncoding | SF_FORMAT_RAW; info.channels = mChannelChoice->GetSelection() + 1; info.samplerate = 44100; //mOK = (wxButton *)wxWindow::FindWindowById(wxID_OK, this); if (sf_format_check(&info)) { mOK->Enable(true); return; } // Try it with 1-channel info.channels = 1; if (sf_format_check(&info)) { mChannelChoice->SetSelection(0); mOK->Enable(true); return; } // Otherwise, this is an unsupported format mOK->Enable(false); } // Indentation settings for Vim and Emacs and unique identifier for Arch, a // version control system. Please do not modify past this point. // // Local Variables: // c-basic-offset: 3 // indent-tabs-mode: nil // End: // // vim: et sts=3 sw=3 // arch-tag: 3e6ead61-1ef2-4518-a622-523f1efebb9a