void TTrackball::OnIdle(wxIdleEvent& event)
{
    long elapsed = wxGetElapsedTime(false);

    // 'elapsed' can be less than 'previous' if the timer gets reset somewhere else.
    if (elapsed < previous) {
        previous = elapsed;
    }

    // Animate the shader if at least one millisecond has elapsed.
    else if (elapsed - previous > 0) {
        canvas->Animate(elapsed - previous);
        previous = elapsed;
    }

    //
    // When not showing frames per second, wait enough between frames to not exceed a maximum frame rate.
    // The proper way of doing this is wait-for-vertical-sync, accessible via the display applet.
    // (Some older 3Dlabs products do not support the wglSwapControl extension.)
    //

    // If wglSwapInterval isn't available, wait for some time to elapse.
    if (wxGetApp().CapFps() && !wglSwapIntervalEXT) {
        if (!inertiaTheta || elapsed < Delay) {
            event.RequestMore();
            event.Skip();
            return;
        }

        // Reset timer.
        wxGetElapsedTime(true);
        previous = 0;
    } else {
        // Recalculate the fps every second.
        if (elapsed > 1000) {
            // Reset timer.
            wxGetElapsedTime(true);
            previous = 0;

            // Update the fps display counter on the status bar.
            wxGetApp().UpdateFps((float) frames * 1000.0f / (float) elapsed);
            frames = 0;
        }
        ++frames;
    }

    // Continue spinning the model.
    glLoadIdentity();
    vec3 offset = wxGetApp().Frame()->GetCenter();
    glTranslate(offset);
    glRotatef(-inertiaTheta, inertiaAxis.x, inertiaAxis.y, inertiaAxis.z);
    glTranslate(-offset);
    glMultMatrixf((float*) &xform);
    glGetFloatv(GL_MODELVIEW_MATRIX, (float*) &xform);
    canvas->Update();
    event.Skip();
}
void TTrackball::Reset(bool all)
{
    previous = wxGetElapsedTime(true);
    frames = 0;

    startZoom = StartZoom;
    if (canvas)
        canvas->SetZoom(startZoom);

    Stop();
    vPrev = vec3(0, 0, 0);
    vInc = vec3(0, 0, 0);
    inertiaTheta = all ? (wxGetApp().Simple() ? 0 : -1) : 0;
    inertiaAxis = vec3(0, 1, 0);
    validStart = false;
    xform.identity();
    wxStartTimer();
}
Beispiel #3
0
void SGCanvasMouseHandler::Reset()
{
    previous = wxGetElapsedTime(true);
    frames = 0.0f;

    startZoom = StartZoom;
    if (canvas)
    {
        canvas->SetZoom(startZoom);
    }
    Stop();
    vPrev = vec3(0.0f, 0.0f, 0.0f);
    vInc = vec3(0.0f, 0.0f, 0.0f);
    inertiaTheta = 0.0f;
    inertiaAxis = vec3(0.0f, 1.0f, 0.0f);
    validStart = false;
    xform.identity();
    wxStartTimer();
}
Beispiel #4
0
void DirManager::CleanTempDir()
{
   wxString fname;
   wxStringList fnameList;
   int count = 0;

   // XXX: is this too destructive, to delete everything?
   fname = wxFindFirstFile((const char *) (temp + wxFILE_SEP_PATH + "b*"));
   while (fname != "") {
      count++;
      fnameList.Add(fname);
      fname = wxFindNextFile();
   }

   wxChar **array = fnameList.ListToArray();

   wxProgressDialog *progress = NULL;

   //wxYield();
   wxStartTimer();

   for (int i = 0; i < count; i++) {
      wxString fileName = array[i];
      wxRemoveFile(fileName);

      if (!progress && wxGetElapsedTime(false) > 500)
         progress =
             new wxProgressDialog(_("Progress"),
                                  _("Cleaning up temporary files..."),
                                  1000,
                                  NULL,
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);

      if (progress)
         progress->Update(int ((i * 1000.0) / count));
   }

   if (progress)
      delete progress;

   delete [] array;
}
Beispiel #5
0
void DirManager::CleanTempDir()
{
   wxString fname;
   wxStringList fnameList;
   int count = 0;

   fname = wxFindFirstFile((const char *) (temp + pathChar + "*.auf"));
   while (fname != "") {
      if (fname.Length() >= 5 && fname.Right(3) == "auf") {
         count++;
         fnameList.Add(fname);
      }
      fname = wxFindNextFile();
   }

   wxChar **array = fnameList.ListToArray();

   wxProgressDialog *progress = NULL;

   wxYield();
   wxStartTimer();

   for (int i = 0; i < count; i++) {
      wxString fileName = array[i];
      wxRemoveFile(fileName);

      if (!progress && wxGetElapsedTime(false) > 500)
         progress =
             new wxProgressDialog("Progress",
                                  "Cleaning up temporary files...",
                                  1000,
                                  NULL,
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);

      if (progress)
         progress->Update(int ((i * 1000.0) / count));
   }

   if (progress)
      delete progress;
}
Beispiel #6
0
bool Effect::TotalProgress(double frac)
{
   if (!mProgress && wxGetElapsedTime(false) > 500) {
      mProgress =
         new wxProgressDialog(GetEffectName(),
                              GetEffectAction(),
                              1000,
                              mParent,
                              wxPD_CAN_ABORT |
                              wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
   }
   
   bool cancelling = false;

   if (mProgress) {
      cancelling =
         !mProgress->Update((int)(frac*1000 + 0.5));
   }
   
   return cancelling;
}
bool Go(void)
{
#ifndef NO_GUI
  ChooseInputFile();
  ChooseOutputFile();
#endif

  if (InputFile.empty() || OutputFile.empty() || stopRunning)
    return false;

#ifndef NO_GUI
  if (isInteractive)
  {
    wxChar buf[300];
    wxString str = wxFileNameFromPath(InputFile);

    wxSnprintf(buf, sizeof(buf), _T("Tex2RTF [%s]"), (const wxChar*) str);
    frame->SetTitle(buf);
  }

  wxStartTimer();
#endif

  // Find extension-less filename
  wxStrcpy(FileRoot, OutputFile.c_str());
  StripExtension(FileRoot);

  if (truncateFilenames && convertMode == TEX_HTML)
  {
    // Truncate to five characters. This ensures that
    // we can generate DOS filenames such as thing999. But 1000 files
    // may not be enough, of course...
    wxChar* sName = wxFileNameFromPath( FileRoot);  // this Julian's method is non-destructive reference

    if(sName)
      if(wxStrlen( sName) > 5)
        sName[5] = '\0';  // that should do!
  }

  wxSnprintf(ContentsName, 300, _T("%s.con"), FileRoot);
  wxSnprintf(TmpContentsName, 300, _T("%s.cn1"), FileRoot);
  wxSnprintf(TmpFrameContentsName, 300, _T("%s.frc"), FileRoot);
  wxSnprintf(WinHelpContentsFileName, 300, _T("%s.cnt"), FileRoot);
  wxSnprintf(RefFileName, 300, _T("%s.ref"), FileRoot);

  TexPathList.EnsureFileAccessible(InputFile);
  if (!bulletFile)
  {
    wxString s = TexPathList.FindValidPath(_T("bullet.bmp"));
    if (!s.empty())
    {
      wxString str = wxFileNameFromPath(s);
      bulletFile = copystring(str);
    }
  }

  if (wxFileExists(RefFileName))
    ReadTexReferences(RefFileName);

  bool success = false;

  if (!InputFile.empty() && !OutputFile.empty())
  {
    if (!wxFileExists(InputFile))
    {
      OnError(_T("Cannot open input file!"));
      TexCleanUp();
      return false;
    }
#if !defined(NO_GUI) && wxUSE_STATUSBAR
    if (isInteractive)
    {
      wxString buf;
      buf.Printf(_T("Working, pass %d...Click CLOSE to abort"), passNumber);
      frame->SetStatusText((wxChar *)buf.c_str());
    }
#endif
    OkToClose = false;
    OnInform(_T("Reading LaTeX file..."));
    TexLoadFile(InputFile);

    if (stopRunning)
    {
        OkToClose = true;
        return false;
    }

    switch (convertMode)
    {
      case TEX_RTF:
      {
        success = RTFGo();
        break;
      }
      case TEX_XLP:
      {
        success = XLPGo();
        break;
      }
      case TEX_HTML:
      {
        success = HTMLGo();
        break;
      }
    }
  }
  if (stopRunning)
  {
    OnInform(_T("*** Aborted by user."));
    success = false;
    stopRunning = false;
    OkToClose = true;
  }

  if (success)
  {
    WriteTexReferences(RefFileName);
    TexCleanUp();
    startedSections = false;

    wxString buf;
#ifndef NO_GUI
    long tim = wxGetElapsedTime();
    buf.Printf(_T("Finished PASS #%d in %ld seconds.\n"), passNumber, (long)(tim/1000.0));
    OnInform((wxChar *)buf.c_str());

    if (errorCount)
    {
        buf.Printf(_T("Errors encountered during this pass: %lu\n"), errorCount);
        OnInform((wxChar *)buf.c_str());
    }

#if wxUSE_STATUSBAR
    if (isInteractive)
    {
      buf.Printf(_T("Done, %d %s."), passNumber, (passNumber > 1) ? _T("passes") : _T("pass"));
      frame->SetStatusText((wxChar *)buf.c_str());
    }
#endif // wxUSE_STATUSBAR
#else
    buf.Printf(_T("Done, %d %s."), passNumber, (passNumber > 1) ? _T("passes") : _T("pass"));
    OnInform((wxChar *)buf.c_str());
    if (errorCount)
    {
        buf.Printf(_T("Errors encountered during this pass: %lu\n"), errorCount);
        OnInform((wxChar *)buf.c_str());
    }
#endif
    passNumber ++;
    errorCount = 0;
    OkToClose = true;
    return true;
  }

  TexCleanUp();
  startedSections = false;

#if !defined(NO_GUI) && wxUSE_STATUSBAR
  frame->SetStatusText(_T("Aborted by user."));
#endif // GUI

  OnInform(_T("Sorry, unsuccessful."));
  OkToClose = true;
  return false;
}
Beispiel #8
0
bool ImportOGG(wxWindow * parent,
               wxString Filename, WaveTrack ** channels[],
               int *numChannels, DirManager * dirManager)
{

   wxFFile file(Filename, "rb");

   if (!file.IsOpened()) {
      // No need for a message box, it's done automatically (but how?)
      return false;
   }

   OggVorbis_File vf;
   int err = ov_open(file.fp(), &vf, NULL, 0);

   if (err < 0) {
      wxString message;

      switch (err) {
         case OV_EREAD:
            message = _("Media read error");
            break;
         case OV_ENOTVORBIS:
            message = _("Not an Ogg Vorbis file");
            break;
         case OV_EVERSION:
            message = _("Vorbis version mismatch");
            break;
         case OV_EBADHEADER:
            message = _("Invalid Vorbis bitstream header");
            break;
         case OV_EFAULT:
            message = _("Internal logic fault");
            break;
      }

      wxMessageBox(message);
      file.Close();
      return false;
   }

   /* -1 is for the current logical bitstream */
   vorbis_info *vi = ov_info(&vf, -1);

   *numChannels = vi->channels;
   *channels = new WaveTrack *[*numChannels];

   int c;
   for (c = 0; c < *numChannels; c++) {
      (*channels)[c] = new WaveTrack(dirManager);
      (*channels)[c]->SetRate(vi->rate);
      (*channels)[c]->SetSampleFormat(int16Sample);

      switch (c) {
         case 0:
            (*channels)[c]->SetChannel(VTrack::LeftChannel);
            break;
         case 1:
            (*channels)[c]->SetChannel(VTrack::RightChannel);
            break;
         default:
            (*channels)[c]->SetChannel(VTrack::MonoChannel);
      }
   }

   if (*numChannels == 2)
      (*channels)[0]->SetLinked(true);

   wxProgressDialog *progress = NULL;

   wxYield();
   wxStartTimer();

/* The number of bytes to get from the codec in each run */
#define CODEC_TRANSFER_SIZE 4096
   
   const int bufferSize = 1048576;
   short *mainBuffer = new short[CODEC_TRANSFER_SIZE];

   short **buffers = new short *[*numChannels];
   for (int i = 0; i < *numChannels; i++) {
      buffers[i] = new short[bufferSize];
   }

   /* determine endianness (clever trick courtesy of Nicholas Devillard,
    * (http://www.eso.org/~ndevilla/endian/) */
   int testvar = 1, endian;
   if(*(char *)&testvar)
      endian = 0;  // little endian
   else
      endian = 1;  // big endian

   /* number of samples currently in each channel's buffer */
   int bufferCount = 0;
   bool cancelled = false;
   long bytesRead = 0;
   long samplesRead = 0;
   int bitstream = 0;

   do {
      bytesRead = ov_read(&vf, (char *) mainBuffer, CODEC_TRANSFER_SIZE,
                          endian,
                          2,    // word length (2 for 16 bit samples)
                          1,    // signed
                          &bitstream);
      samplesRead = bytesRead / *numChannels / sizeof(short);

      if (samplesRead + bufferCount > bufferSize) {
         for (c = 0; c < *numChannels; c++)
            (*channels)[c]->Append((samplePtr)buffers[c],
                                   int16Sample,
                                   bufferCount);
         bufferCount = 0;
      }

      /* Un-interleave */
      for (int s = 0; s < samplesRead; s++)
         for (c = 0; c < *numChannels; c++)
            buffers[c][s + bufferCount] =
                mainBuffer[s * (*numChannels) + c];

      bufferCount += samplesRead;


      if (!progress && wxGetElapsedTime(false) > 500)
         progress = new wxProgressDialog(_("Import"),
                                         _("Importing Ogg Vorbis File..."),
                                         1000,
                                         parent,
                                         wxPD_CAN_ABORT |
                                         wxPD_REMAINING_TIME |
                                         wxPD_AUTO_HIDE);

      if (progress)
         cancelled = !progress->Update(ov_time_tell(&vf) * 1000 /
                                       ov_time_total(&vf, bitstream));

   } while (!cancelled && bytesRead != 0 && bitstream == 0);

   /* ...the rest is de-allocation */
   ov_clear(&vf);
   file.Detach();    // so that it doesn't try to close the file (ov_clear()
                     // did that already)

   delete[]mainBuffer;

   for (c = 0; c < *numChannels; c++)
      delete[]buffers[c];
   delete[]buffers;

   if (progress)
      delete progress;

   if (cancelled) {
      for (c = 0; c < *numChannels; c++)
         delete(*channels)[c];
      delete[] * channels;

      return false;
   }

   return true;

}
Beispiel #9
0
//TODO-MB: wouldn't it make more sense to DELETE the time track after 'mix and render'?
void MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
                  double rate, sampleFormat format,
                  double startTime, double endTime,
                  WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
{
   uLeft.reset(), uRight.reset();

   // This function was formerly known as "Quick Mix".
   Track *t;
   bool mono = false;   /* flag if output can be mono without loosing anything*/
   bool oneinput = false;  /* flag set to true if there is only one input track
                              (mono or stereo) */

   TrackListIterator iter(tracks);
   SelectedTrackListOfKindIterator usefulIter(Track::Wave, tracks);
   // this only iterates tracks which are relevant to this function, i.e.
   // selected WaveTracks. The tracklist is (confusingly) the list of all
   // tracks in the project

   int numWaves = 0; /* number of wave tracks in the selection */
   int numMono = 0;  /* number of mono, centre-panned wave tracks in selection*/
   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         numWaves++;
         float pan = ((WaveTrack*)t)->GetPan();
         if (t->GetChannel() == Track::MonoChannel && pan == 0)
            numMono++;
      }
      t = iter.Next();
   }

   if (numMono == numWaves)
      mono = true;

   /* the next loop will do two things at once:
    * 1. build an array of all the wave tracks were are trying to process
    * 2. determine when the set of WaveTracks starts and ends, in case we
    *    need to work out for ourselves when to start and stop rendering.
    */

   double mixStartTime = 0.0;    /* start time of first track to start */
   bool gotstart = false;  // flag indicates we have found a start time
   double mixEndTime = 0.0;   /* end time of last track to end */
   double tstart, tend;    // start and end times for one track.

   WaveTrackConstArray waveArray;
   t = iter.First();

   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         waveArray.push_back(static_cast<WaveTrack *>(t));
         tstart = t->GetStartTime();
         tend = t->GetEndTime();
         if (tend > mixEndTime)
            mixEndTime = tend;
         // try and get the start time. If the track is empty we will get 0,
         // which is ambiguous because it could just mean the track starts at
         // the beginning of the project, as well as empty track. The give-away
         // is that an empty track also ends at zero.

         if (tstart != tend) {
            // we don't get empty tracks here
            if (!gotstart) {
               // no previous start, use this one unconditionally
               mixStartTime = tstart;
               gotstart = true;
            } else if (tstart < mixStartTime)
               mixStartTime = tstart;  // have a start, only make it smaller
         }  // end if start and end are different
      }  // end if track is a selected WaveTrack.
      /** @TODO: could we not use a SelectedTrackListOfKindIterator here? */
      t = iter.Next();
   }

   /* create the destination track (NEW track) */
   if ((numWaves == 1) || ((numWaves == 2) && (usefulIter.First()->GetLink() != NULL)))
      oneinput = true;
   // only one input track (either 1 mono or one linked stereo pair)

   auto mixLeft = trackFactory->NewWaveTrack(format, rate);
   if (oneinput)
      mixLeft->SetName(usefulIter.First()->GetName()); /* set name of output track to be the same as the sole input track */
   else
      mixLeft->SetName(_("Mix"));
   mixLeft->SetOffset(mixStartTime);
   decltype(mixLeft) mixRight{};
   if (mono) {
      mixLeft->SetChannel(Track::MonoChannel);
   }
   else {
      mixRight = trackFactory->NewWaveTrack(format, rate);
      if (oneinput) {
         if (usefulIter.First()->GetLink() != NULL)   // we have linked track
            mixLeft->SetName(usefulIter.First()->GetLink()->GetName()); /* set name to match input track's right channel!*/
         else
            mixLeft->SetName(usefulIter.First()->GetName());   /* set name to that of sole input channel */
      }
      else
         mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(Track::LeftChannel);
      mixRight->SetChannel(Track::RightChannel);
      mixRight->SetOffset(mixStartTime);
      mixLeft->SetLinked(true);
   }



   int maxBlockLen = mixLeft->GetIdealBlockSize();

   // If the caller didn't specify a time range, use the whole range in which
   // any input track had clips in it.
   if (startTime == endTime) {
      startTime = mixStartTime;
      endTime = mixEndTime;
   }

   Mixer mixer(waveArray,
      Mixer::WarpOptions(tracks->GetTimeTrack()),
      startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
      rate, format);

   ::wxSafeYield();

   int updateResult = eProgressSuccess;
   {
      ProgressDialog progress(_("Mix and Render"),
         _("Mixing and rendering tracks"));

      while (updateResult == eProgressSuccess) {
         sampleCount blockLen = mixer.Process(maxBlockLen);

         if (blockLen == 0)
            break;

         if (mono) {
            samplePtr buffer = mixer.GetBuffer();
            mixLeft->Append(buffer, format, blockLen);
         }
         else {
            samplePtr buffer;
            buffer = mixer.GetBuffer(0);
            mixLeft->Append(buffer, format, blockLen);
            buffer = mixer.GetBuffer(1);
            mixRight->Append(buffer, format, blockLen);
         }

         updateResult = progress.Update(mixer.MixGetCurrentTime() - startTime, endTime - startTime);
      }
   }

   mixLeft->Flush();
   if (!mono)
      mixRight->Flush();
   if (updateResult == eProgressCancelled || updateResult == eProgressFailed)
   {
      return;
   }
   else {
      uLeft = std::move(mixLeft),
         uRight = std::move(mixRight);
#if 0
   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

   // Note: these shouldn't be translated - they're for debugging
   // and profiling only.
   printf("      Tracks: %d\n", numWaves);
   printf("  Mix length: %f sec\n", totalTime);
   printf("Elapsed time: %f sec\n", elapsedTime);
   printf("Max number of tracks to mix in real time: %f\n", maxTracks);
#endif
   }
}
Beispiel #10
0
bool ImportPCM(wxWindow * parent,
               wxString fName, 
               WaveTrack ** channels[],
               int *numChannels,
               DirManager * dirManager)
{
   SF_INFO    info;
   SNDFILE   *fp;

   fp = sf_open_read(fName, &info);

   if (!fp) {
      char str[1000];
      sf_error_str((SNDFILE *)NULL, str, 1000);
      wxMessageBox(str);

      return false;
   }

   wxString progressStr;
   wxString formatName;
   for(int z=0; z<gNumPCMFormats; z++)
      if ((info.format & SF_FORMAT_TYPEMASK) == gPCMFormats[z].id)
         formatName = gPCMFormats[z].name;
   progressStr.Printf("Importing %s file...",
                      formatName);

   *numChannels = info.channels;
   *channels = new WaveTrack*[*numChannels];

   int c;
   for(c=0; c<*numChannels; c++) {
      (*channels)[c] = new WaveTrack(dirManager);
      (*channels)[c]->rate = info.samplerate;
      (*channels)[c]->name = TrackNameFromFileName(fName);
      (*channels)[c]->channel = VTrack::MonoChannel;
   }

   if (*numChannels == 2) {
      (*channels)[0]->channel = VTrack::LeftChannel;
      (*channels)[1]->channel = VTrack::RightChannel;
      (*channels)[0]->linked = true;
   }

   sampleCount fileTotalFrames = (sampleCount)info.samples;
   sampleCount maxBlockSize = (sampleCount)WaveTrack::GetIdealBlockSize();

   wxString copyEdit =
       gPrefs->Read("/FileFormats/CopyOrEditUncompressedData", "edit");

   // Fall back to "edit" if it doesn't match anything else
   bool doEdit = true;          
   if (copyEdit.IsSameAs("copy", false))
      doEdit = false;

   if (doEdit) {

      // If this mode has been selected, we form the tracks as
      // aliases to the files we're editing, i.e. ("foo.wav", 12000-18000)
      // instead of actually making fresh copies of the samples.

      wxProgressDialog *progress = NULL;
      wxYield();
      wxStartTimer();
      wxBusyCursor busy;

      bool cancelling = false;

      for (sampleCount i = 0; i < fileTotalFrames; i += maxBlockSize) {
         sampleCount blockLen = maxBlockSize;
         if (i + blockLen > fileTotalFrames)
            blockLen = fileTotalFrames - i;

         for(c=0; c<*numChannels; c++)
            (*channels)[c]->AppendAlias(fName, i, blockLen, c);

         if (!progress && wxGetElapsedTime(false) > 500) {
            progress =
                new wxProgressDialog("Import", progressStr,
                                     1000,
                                     parent,
                                     wxPD_CAN_ABORT |
                                     wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
         }
         if (progress) {
            cancelling = !progress->Update((int)((i*1000.0)/fileTotalFrames));

            if (cancelling)
               i = fileTotalFrames;
         }
      }

      //printf("Time elapsed: %d\n", wxGetElapsedTime());

      if (progress)
         delete progress;

      if (cancelling) {
         for(c=0; c<*numChannels; c++)
            delete (*channels)[c];
         delete[] (*channels);
         *channels = NULL;

         return false;
      }

      return true;
   }

   // Otherwise, we're in the "copy" mode, where we read in the actual
   // samples from the file and store our own local copy of the
   // samples in the tracks.

   sampleType *srcbuffer = new short[maxBlockSize * (*numChannels)];
   sampleType *buffer = new short[maxBlockSize];

   unsigned long framescompleted = 0;

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;

   bool cancelling = false;

   long block;
   do {
      block = maxBlockSize;
      block = sf_readf_short(fp, srcbuffer, block);

      if (block) {
         for(c=0; c<(*numChannels); c++) {
            for(int j=0; j<block; j++)
               buffer[j] = srcbuffer[(*numChannels)*j+c];
            (*channels)[c]->Append(buffer, block);
         }

         framescompleted += block;
      }

      if (!progress && wxGetElapsedTime(false) > 500) {
         progress =
            new wxProgressDialog("Import", progressStr,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         int progressvalue = (framescompleted > fileTotalFrames) ?
             fileTotalFrames : framescompleted;

         cancelling =
            !progress->Update((int)((progressvalue*1000.0)/fileTotalFrames));

         if (cancelling)
            block = 0;
      }
   } while (block > 0);

   sf_close(fp);

   //printf("Time elapsed: %d\n", wxGetElapsedTime());

   if (progress)
      delete progress;

   delete[] srcbuffer;
   delete[] buffer;

   if (cancelling) {
      for(c=0; c<*numChannels; c++)
         delete (*channels)[c];
      delete[] (*channels);
      *channels = NULL;

      return false;
   }

   return true;
}
Beispiel #11
0
bool ExportOGG(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
   double    rate    = project->GetRate();
   wxWindow  *parent = project;
   TrackList *tracks = project->GetTracks();
   double    quality = (gPrefs->Read("/FileFormats/OggExportQuality", 50)/(float)100.0);

   wxLogNull logNo;            // temporarily disable wxWindows error messages 
   bool      cancelling = false;

   wxFFile outFile(fName, "wb");

   if(!outFile.IsOpened()) {
      wxMessageBox(_("Unable to open target file for writing"));
      return false;
   }

   // All the Ogg and Vorbis encoding data
   ogg_stream_state stream;
   ogg_page         page;
   ogg_packet       packet;

   vorbis_info      info;
   vorbis_comment   comment;
   vorbis_dsp_state dsp;
   vorbis_block     block;

   // Encoding setup
   vorbis_info_init(&info);
   vorbis_encode_init_vbr(&info, stereo ? 2 : 1, int(rate + 0.5), quality);

   vorbis_comment_init(&comment);
   // If we wanted to add comments, we would do it here

   // Set up analysis state and auxiliary encoding storage
   vorbis_analysis_init(&dsp, &info);
   vorbis_block_init(&dsp, &block);

   // Set up packet->stream encoder.  According to encoder example,
   // a random serial number makes it more likely that you can make
   // chained streams with concatenation.
   srand(time(NULL));
   ogg_stream_init(&stream, rand());

   // First we need to write the required headers:
   //    1. The Ogg bitstream header, which contains codec setup params
   //    2. The Vorbis comment header
   //    3. The bitstream codebook.
   //
   // After we create those our responsibility is complete, libvorbis will
   // take care of any other ogg bistream constraints (again, according
   // to the example encoder source)
   ogg_packet bitstream_header;
   ogg_packet comment_header;
   ogg_packet codebook_header;

   vorbis_analysis_headerout(&dsp, &comment, &bitstream_header, &comment_header,
         &codebook_header);

   // Place these headers into the stream
   ogg_stream_packetin(&stream, &bitstream_header);
   ogg_stream_packetin(&stream, &comment_header);
   ogg_stream_packetin(&stream, &codebook_header);

   // Flushing these headers now guarentees that audio data will
   // start on a new page, which apparently makes streaming easier
   ogg_stream_flush(&stream, &page);
   outFile.Write(page.header, page.header_len);
   outFile.Write(page.body, page.body_len);

   double t = t0;
   bool   done = false;
   wxProgressDialog *progress = NULL;

   wxYield();
   wxStartTimer();

   while(!done && !cancelling){
      float       deltat = (float)SAMPLES_PER_RUN / rate;
      sampleCount samplesThisRun = SAMPLES_PER_RUN;
      Mixer       *mixer = new Mixer(stereo ? 2 : 1, SAMPLES_PER_RUN, 
            /* interleaved = */ false, rate, floatSample);

      if(t + deltat > t1) {
         done = true;
         deltat = t1 - t;
         samplesThisRun = int(deltat * rate + 0.5);
      }
      
      mixer->Clear();

      TrackListIterator iter(tracks);
      Track *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == Track::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == Track::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == Track::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == Track::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }
      
      float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN);
      
      float *left = (float *)mixer->GetBuffer(0);
      memcpy(vorbis_buffer[0], left, sizeof(float)*SAMPLES_PER_RUN);

      if(stereo) {
         float *right = (float *)mixer->GetBuffer(1);
         memcpy(vorbis_buffer[1], right, sizeof(float)*SAMPLES_PER_RUN);
      }

      // tell the encoder how many samples we have
      vorbis_analysis_wrote(&dsp, samplesThisRun);

      // I don't understand what this call does, so here is the comment
      // from the example, verbatim:
      //
      //    vorbis does some data preanalysis, then divvies up blocks
      //    for more involved (potentially parallel) processing. Get
      //    a single block for encoding now
      while(vorbis_analysis_blockout(&dsp, &block) == 1) {

         // analysis, assume we want to use bitrate management
         vorbis_analysis(&block, NULL);
         vorbis_bitrate_addblock(&block);

         while(vorbis_bitrate_flushpacket(&dsp, &packet)) {

            // add the packet to the bitstream
            ogg_stream_packetin(&stream, &packet);
            int result = ogg_stream_pageout(&stream, &page);

            if(result != 0) {
               outFile.Write(page.header, page.header_len);
               outFile.Write(page.body, page.body_len);
            }
         }
      }

      if(progress)
         cancelling = !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      else if(wxGetElapsedTime(false) > 500) {
            
         wxString message = selectionOnly ?
            _("Exporting the selected audio as Ogg Vorbis") :
            _("Exporting the entire project as Ogg Vorbis");

         progress = new wxProgressDialog(
               _("Export"),
               message,
               1000,
               parent,
               wxPD_CAN_ABORT | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }

      delete mixer;
      t += deltat;
   }

   outFile.Close();

   if(progress)
      delete progress;

   return true;
}
Beispiel #12
0
// static
void DirManager::CleanTempDir(bool startup)
{
    wxString fname;
    wxStringList fnameList;
    int count = 0;

    if (dontDeleteTempFiles)
        return;

    // XXX: is this too destructive, to delete everything?
    fname = wxFindFirstFile((const char *) (temp + wxFILE_SEP_PATH + "b*"));
    while (fname != "") {
        count++;
        fnameList.Add(fname);
        fname = wxFindNextFile();
    }

    if (count == 0)
        return;

    if (startup) {
        wxString prompt =
            _("Audacity found temporary files that were not deleted or saved\n"
              "the last time you used Audacity.\n\n"
              "Audacity can't recover them automatically, but if you choose not\n"
              "to delete them, you can recover them manually.\n\n"
              "Delete temporary files?");

        int action = wxMessageBox(prompt,
                                  "Warning",
                                  wxYES_NO | wxICON_EXCLAMATION,
                                  NULL);

        if (action != wxYES) {
            dontDeleteTempFiles = true;
            return;
        }
    }

    wxChar **array = fnameList.ListToArray();

    wxProgressDialog *progress = NULL;

    //wxYield();
    wxStartTimer();

    for (int i = 0; i < count; i++) {
        wxString fileName = array[i];
        wxRemoveFile(FILENAME(fileName));

        if (!progress && wxGetElapsedTime(false) > 500)
            progress =
                new wxProgressDialog(_("Progress"),
                                     _("Cleaning up temporary files..."),
                                     1000,
                                     NULL,
                                     wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);

        if (progress)
            progress->Update(int ((i * 1000.0) / count));
    }

    if (progress)
        delete progress;

    delete [] array;
}
Beispiel #13
0
bool ExportPCM(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
   double       rate = project->GetRate();
   wxWindow    *parent = project;
   TrackList   *tracks = project->GetTracks();
   int          format = ReadExportFormatPref();
   int          formatBits = ReadExportFormatBitsPref();
   wxString     formatStr;
   SF_INFO      info;
   SNDFILE     *sf;
   int          err;

   formatStr = sf_header_name(format & SF_FORMAT_TYPEMASK);

   // Use libsndfile to export file

   info.samplerate = (unsigned int)(rate + 0.5);
   info.samples = (unsigned int)((t1 - t0)*rate + 0.5);
   info.channels = stereo? 2: 1;
   info.pcmbitwidth = formatBits;
   info.format = format;
   info.sections = 1;
   info.seekable = 0;

   // If we can't export exactly the format they requested,
   // try the default format for that header type, and try
   // 16-bit samples.
   if (!sf_format_check(&info))
      info.format = (info.format & SF_FORMAT_TYPEMASK);
   if (!sf_format_check(&info))
      info.pcmbitwidth = 16;
   if (!sf_format_check(&info)) {
      wxMessageBox(_("Cannot export audio in this format."));
      return false;
   }

   sf = sf_open_write((const char *)fName, &info);
   if (!sf) {
      wxMessageBox(wxString::Format(_("Cannot export audio to %s"),
                                    (const char *)fName));
      return false;
   }

   double timeStep = 10.0;      // write in blocks of 10 secs

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;

   double t = t0;

   while (t < t1 && !cancelling) {

      double deltat = timeStep;
      if (t + deltat > t1)
         deltat = t1 - t;

      sampleCount numSamples = int (deltat * rate + 0.5);

      Mixer *mixer = new Mixer(stereo ? 2 : 1, numSamples, true, rate);
      wxASSERT(mixer);
      mixer->Clear();

      TrackListIterator iter(tracks);
      VTrack *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == VTrack::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == VTrack::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }

      sampleType *mixed = mixer->GetBuffer();

      sf_writef_short(sf, mixed, numSamples);

      t += deltat;

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (selectionOnly)
            message =
                wxString::
                Format(_("Exporting the selected audio as a %s file"),
                       (const char *) formatStr);
         else
            message =
                wxString::
                Format(_("Exporting the entire project as a %s file"),
                       (const char *) formatStr);

         progress =
             new wxProgressDialog(_("Export"),
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         cancelling =
             !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      }

      delete mixer;
   }

   err = sf_close(sf);

   if (err) {
      char buffer[1000];
      sf_error_str(sf, buffer, 1000);
      wxMessageBox(wxString::Format
                   (_("Error (file may not have been written): %s"),
                    buffer));
   }

#ifdef __WXMAC__

   FSSpec spec;

   wxMacFilename2FSSpec(fName, &spec);

   FInfo finfo;
   if (FSpGetFInfo(&spec, &finfo) == noErr) {
      finfo.fdType = sf_header_mactype(format & SF_FORMAT_TYPEMASK);
      finfo.fdCreator = AUDACITY_CREATOR;

      FSpSetFInfo(&spec, &finfo);
   }
#endif

   if (progress)
      delete progress;

   return true;
}
Beispiel #14
0
bool ExportPCM(AudacityProject *project,
               wxString format, bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
    wxMessageBox("In process of being rewritten, sorry...");

#if 0

    double rate = project->GetRate();
    wxWindow *parent = project;
    TrackList *tracks = project->GetTracks();

    int header = SND_HEAD_NONE;
#ifdef __WXMAC__
    bool trackMarkers = false;
#endif

    if (format == "WAV")
        header = SND_HEAD_WAVE;
    else if (format == "AIFF")
        header = SND_HEAD_AIFF;
    else if (format == "IRCAM")
        header = SND_HEAD_IRCAM;
    else if (format == "AU")
        header = SND_HEAD_NEXT;
#ifdef __WXMAC__
    else if (format == "AIFF with track markers") {
        header = SND_HEAD_AIFF;
        trackMarkers = true;
    }
#endif


    // Use snd library to export file

    snd_node sndfile;
    snd_node sndbuffer;

    sndfile.device = SND_DEVICE_FILE;
    sndfile.write_flag = SND_WRITE;
    strcpy(sndfile.u.file.filename, (const char *) fName);
    sndfile.u.file.file = 0;
    sndfile.u.file.header = header;
    sndfile.u.file.byte_offset = 0;
    sndfile.u.file.end_offset = 0;
    sndfile.u.file.swap = 0;
    sndfile.format.channels = stereo ? 2 : 1;
    sndfile.format.mode = SND_MODE_PCM;  // SND_MODE_FLOAT
    sndfile.format.bits = 16;
    sndfile.format.srate = int (rate + 0.5);

    int err;
    long flags = 0;

    err = snd_open(&sndfile, &flags);
    if (err) {
        wxMessageBox("Could not write to file.");
        return false;
    }

    sndbuffer.device = SND_DEVICE_MEM;
    sndbuffer.write_flag = SND_READ;
    sndbuffer.u.mem.buffer_max = 0;
    sndbuffer.u.mem.buffer = 0;
    sndbuffer.u.mem.buffer_len = 0;
    sndbuffer.u.mem.buffer_pos = 0;
    sndbuffer.format.channels = stereo ? 2 : 1;
    sndbuffer.format.mode = SND_MODE_PCM;        // SND_MODE_FLOAT
    sndbuffer.format.bits = 16;
    sndbuffer.format.srate = int (rate + 0.5);

    double timeStep = 10.0;      // write in blocks of 10 secs

    wxProgressDialog *progress = NULL;
    wxYield();
    wxStartTimer();
    wxBusyCursor busy;
    bool cancelling = false;

    double t = t0;

    while (t < t1 && !cancelling) {

        double deltat = timeStep;
        if (t + deltat > t1)
            deltat = t1 - t;

        sampleCount numSamples = int (deltat * rate + 0.5);

        Mixer *mixer = new Mixer(stereo ? 2 : 1, numSamples, true, rate);
        wxASSERT(mixer);
        mixer->Clear();

        char *buffer = new char[numSamples * 2 * sndbuffer.format.channels];
        wxASSERT(buffer);

        TrackListIterator iter(tracks);
        VTrack *tr = iter.First();
        while (tr) {
            if (tr->GetKind() == VTrack::Wave) {
                if (tr->selected || !selectionOnly) {
                    if (tr->channel == VTrack::MonoChannel)
                        mixer->MixMono((WaveTrack *) tr, t, t + deltat);
                    if (tr->channel == VTrack::LeftChannel)
                        mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
                    if (tr->channel == VTrack::RightChannel)
                        mixer->MixRight((WaveTrack *) tr, t, t + deltat);
                }
            }
            tr = iter.Next();
        }

        sampleType *mixed = mixer->GetBuffer();

        long b2 = snd_convert(&sndfile, buffer,   // to
                              &sndbuffer, mixed, numSamples);     // from

        snd_write(&sndfile, buffer, b2);

        t += deltat;

        if (!progress && wxGetElapsedTime(false) > 500) {

            wxString message;

            if (selectionOnly)
                message =
                    wxString::
                    Format("Exporting the selected audio as a %s file",
                           (const char *) format);
            else
                message =
                    wxString::
                    Format("Exporting the entire project as a %s file",
                           (const char *) format);

            progress =
                new wxProgressDialog("Export",
                                     message,
                                     1000,
                                     parent,
                                     wxPD_CAN_ABORT |
                                     wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
        }
        if (progress) {
            cancelling =
                !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
        }

        delete mixer;
        delete[]buffer;
    }

    snd_close(&sndfile);

#ifdef __WXMAC__

    FSSpec spec;

    wxMacFilename2FSSpec(fName, &spec);

    if (trackMarkers) {
        // Export the label track as "CD Spin Doctor" files

        LabelTrack *labels = NULL;
        TrackListIterator iter(tracks);
        VTrack *t = iter.First();
        while (t && !labels) {
            if (t->GetKind() == VTrack::Label)
                labels = (LabelTrack *) t;
            t = iter.Next();
        }
        if (labels) {
            FSpCreateResFile(&spec, 'AIFF', AUDACITY_CREATOR, 0);
            int resFile = FSpOpenResFile(&spec, fsWrPerm);
            if (resFile == -1) {
                int x = ResError();
            }
            if (resFile != -1) {
                UseResFile(resFile);

                int numLabels = labels->mLabels.Count();
                for (int i = 0; i < numLabels; i++) {
                    int startBlock = (int) (labels->mLabels[i]->t * 75);
                    int lenBlock;
                    if (i < numLabels - 1)
                        lenBlock =
                            (int) ((labels->mLabels[i + 1]->t -
                                    labels->mLabels[i]->t) * 75);
                    else
                        lenBlock =
                            (int) ((tracks->GetMaxLen() -
                                    labels->mLabels[i]->t) * 75);
                    int startSample = startBlock * 1176 + 54;
                    int lenSample = lenBlock * 1176 + 54;

                    Handle theHandle = NewHandle(50);
                    HLock(theHandle);
                    char *data = (char *) (*theHandle);
                    *(int *) &data[0] = startSample;
                    *(int *) &data[4] = lenSample;
                    *(int *) &data[8] = startBlock;
                    *(int *) &data[12] = lenBlock;
                    *(short *) &data[16] = i + 1;

                    wxString title = labels->mLabels[i]->title;
                    if (title.Length() > 31)
                        title = title.Left(31);
                    data[18] = title.Length();
                    strcpy(&data[19], (const char *) title);

                    HUnlock(theHandle);
                    AddResource(theHandle, 'SdCv', 128 + i, "\p");
                }
                CloseResFile(resFile);

                wxMessageBox("Saved track information with file.");
            }
        }
    }

    FInfo finfo;
    if (FSpGetFInfo(&spec, &finfo) == noErr) {
        switch (header) {
        case SND_HEAD_AIFF:
            finfo.fdType = 'AIFF';
            break;
        case SND_HEAD_IRCAM:
            finfo.fdType = 'IRCA';
            break;
        case SND_HEAD_NEXT:
            finfo.fdType = 'AU  ';
            break;
        case SND_HEAD_WAVE:
            finfo.fdType = 'WAVE';
            break;
        }

        finfo.fdCreator = AUDACITY_CREATOR;

        FSpSetFInfo(&spec, &finfo);
    }
#endif

    if (progress)
        delete progress;

    return true;

#endif

    return false;

}
Beispiel #15
0
bool ExportMP3(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
   double rate = project->GetRate();
   wxWindow *parent = project;
   TrackList *tracks = project->GetTracks();

   wxLogNull logNo;             /* temporarily disable wxWindows error messages */

   bool success = GetMP3Exporter()->FindLibrary(parent);
   
   if (!success)
      return false;

   success = GetMP3Exporter()->LoadLibrary();
   if (!success) {
      wxMessageBox(_("Could not open MP3 encoding library!"));
      gPrefs->Write("/MP3/MP3LibPath", wxString(""));

      return false;
   }

   if(!GetMP3Exporter()->ValidLibraryLoaded()) {
      wxMessageBox(_("Not a valid or supported MP3 encoding library!"));      
      gPrefs->Write("/MP3/MP3LibPath", wxString(""));
      
      return false;
   }
   
   /* Open file for writing */

   wxFFile outFile(fName, "wb");
   if (!outFile.IsOpened()) {
      wxMessageBox(_("Unable to open target file for writing"));
      return false;
   }
   
   /* Put ID3 tags at beginning of file */
   
   Tags *tags = project->GetTags();
   if (!tags->ShowEditDialog(project, _("Edit the ID3 tags for the MP3 file")))
      return false;  // used selected "cancel"

   char *id3buffer;
   int id3len;
   bool endOfFile;
   id3len = tags->ExportID3(&id3buffer, &endOfFile);
   if (!endOfFile)
     outFile.Write(id3buffer, id3len);

   /* Export MP3 using DLL */

   long bitrate = gPrefs->Read("/FileFormats/MP3Bitrate", 128);
   GetMP3Exporter()->SetBitrate(bitrate);

   sampleCount inSamples = GetMP3Exporter()->InitializeStream(stereo ? 2 : 1, int(rate + 0.5));
   double timeStep =  (double)inSamples / rate;
   double t = t0;

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;
   long bytes;


   int bufferSize = GetMP3Exporter()->GetOutBufferSize();
   unsigned char *buffer = new unsigned char[bufferSize];
   wxASSERT(buffer);

   while (t < t1 && !cancelling) {

      double deltat = timeStep;
      bool lastFrame = false;
      sampleCount numSamples = inSamples;

      if (t + deltat > t1) {
         lastFrame = true;
         deltat = t1 - t;
         numSamples = int(deltat * rate + 0.5);
      }


      Mixer *mixer = new Mixer(stereo ? 2 : 1, numSamples, true,
                               rate, int16Sample);
      wxASSERT(mixer);
      mixer->Clear();


      TrackListIterator iter(tracks);
      VTrack *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == VTrack::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == VTrack::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == VTrack::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               else if (tr->GetChannel() == VTrack::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }
      
      short *mixed = (short *)mixer->GetBuffer();

      if(lastFrame)
         bytes = GetMP3Exporter()->EncodeRemainder(mixed, numSamples, buffer);
      else
         bytes = GetMP3Exporter()->EncodeBuffer(mixed, buffer);

      outFile.Write(buffer, bytes);

      t += deltat;

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (selectionOnly)
            message =
                wxString::Format(_("Exporting the selected audio as an mp3"));
         else
            message =
                wxString::Format(_("Exporting the entire project as an mp3"));

         progress =
             new wxProgressDialog(_("Export"),
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }

      if (progress) {
         cancelling =
             !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      }

      delete mixer;

   }

   bytes = GetMP3Exporter()->FinishStream(buffer);

   if (bytes)
      outFile.Write(buffer, bytes);
   
   /* Write ID3 tag if it was supposed to be at the end of the file */
   
   if (endOfFile)
      outFile.Write(id3buffer, id3len);
   delete[] id3buffer;

   /* Close file */
   
   outFile.Close();
      
   /* MacOS: set the file type/creator so that the OS knows it's an MP3
      file which was created by Audacity */
      
#ifdef __WXMAC__
   FSSpec spec;
   wxMacFilename2FSSpec(fName, &spec);
   FInfo finfo;
   if (FSpGetFInfo(&spec, &finfo) == noErr) {
      finfo.fdType = 'MP3 ';
      finfo.fdCreator = AUDACITY_CREATOR;

      FSpSetFInfo(&spec, &finfo);
   }
#endif

   if (progress)
      delete progress;

   delete[]buffer;
   
   return true;
}
Beispiel #16
0
bool PCMExporter::Export(const wxString & filename)
{

  mFileName = filename;
  //Unless it has been changed, use the project rate
  if(!mOutRate) 
    mOutRate = mProject->GetRate();
  
  wxWindow    *parent = mProject;
  TrackList   *tracks = mProject->GetTracks();

  wxString     formatStr;
  SF_INFO      info;
  SNDFILE     *sf = NULL;
  int          err;

   formatStr = sf_header_name(mSoundFileFormat & SF_FORMAT_TYPEMASK);

   // Use libsndfile to export file

   info.samplerate = mOutRate;
   info.frames = (unsigned int)((m_t1 - m_t0)*(double)mOutRate + 0.5);
   info.channels = mChannels;
   info.format = mSoundFileFormat;
   info.sections = 1;
   info.seekable = 0;

   // If we can't export exactly the format they requested,
   // try the default format for that header type...
   if (!sf_format_check(&info))
      info.format = (info.format & SF_FORMAT_TYPEMASK);
   if (!sf_format_check(&info)) {
      wxMessageBox(_("Cannot export audio in this format."));
      return false;
   }

   sf = sf_open((const char *)mFileName, SFM_WRITE, &info);
   if (!sf) {
      wxMessageBox(wxString::Format(_("Cannot export audio to %s"),
                                    (const char *)mFileName));
      return false;
   }

   //Determine what format the track is currently in, to avoid
   //multiple conversions.
   sampleFormat format;
   if (sf_subtype_more_than_16_bits(info.format))
      format = floatSample;
   else
      format = int16Sample;

   int maxBlockLen = 44100 * 5;

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;

   int numWaveTracks;
   WaveTrack **waveTracks;
   tracks->GetWaveTracks(mExportSelection, &numWaveTracks, &waveTracks);



  
   Mixer *mixer = new Mixer(numWaveTracks, waveTracks,
                            tracks->GetTimeTrack(),
                            m_t0, m_t1,
                            info.channels, maxBlockLen, true,
                            mInRate, format);

   while(!cancelling) {
      sampleCount numSamples = mixer->Process(maxBlockLen);

      if (numSamples == 0)
         break;
      
      samplePtr mixed = mixer->GetBuffer();

      if (format == int16Sample)
         sf_writef_short(sf, (short *)mixed, numSamples);
      else
         sf_writef_float(sf, (float *)mixed, numSamples);

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (mExportSelection)
            message =
                wxString::
                Format(_("Exporting the selected audio as a %s file"),
                       (const char *) formatStr);
         else
            message =
                wxString::
                Format(_("Exporting the entire project as a %s file"),
                       (const char *) formatStr);

         progress =
             new wxProgressDialog(_("Export"),
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         int progressvalue = int (1000 * ((mixer->MixGetCurrentTime()-m_t0) /
                                          (m_t1-m_t0)));
         cancelling = !progress->Update(progressvalue);
      }
   }

   delete mixer;

   delete[] waveTracks;                            

   err = sf_close(sf);

   if (err) {
      char buffer[1000];
      sf_error_str(sf, buffer, 1000);
      wxMessageBox(wxString::Format
                   (_("Error (file may not have been written): %s"),
                    buffer));
   }

#ifdef __WXMAC__

   FSSpec spec;

   wxMacFilename2FSSpec(fName, &spec);

   FInfo finfo;
   if (FSpGetFInfo(&spec, &finfo) == noErr) {
      finfo.fdType = sf_header_mactype(mSoundFileFormat & SF_FORMAT_TYPEMASK);
      finfo.fdCreator = AUDACITY_CREATOR;

      FSpSetFInfo(&spec, &finfo);
   }
#endif

   if (progress)
      delete progress;

   return true;
}
Beispiel #17
0
bool ExportCL(AudacityProject *project, bool stereo, wxString fName,
              bool selectionOnly, double t0, double t1)
{
   int rate = int(project->GetRate() + 0.5);
   wxWindow *parent = project;
   TrackList *tracks = project->GetTracks();
   
   wxString command = gPrefs->Read("/FileFormats/ExternalProgramExportCommand", "lame - '%f'");
   command.Replace("%f", fName);

   /* establish parameters */
   int channels = stereo ? 2 : 1;
   unsigned long totalSamples = (unsigned long)((t1 - t0) * rate + 0.5);
   unsigned long sampleBytes = totalSamples * channels * SAMPLE_SIZE(int16Sample);
   double timeStep = 10.0;      // write in blocks of 10 secs

   /* fill up the wav header */
   wav_header header;
   header.riffID[0] = 'R';
   header.riffID[1] = 'I';
   header.riffID[2] = 'F';
   header.riffID[3] = 'F';
   header.riffType[0] = 'W';
   header.riffType[1] = 'A';
   header.riffType[2] = 'V';
   header.riffType[3] = 'E';
   header.lenAfterRiff = sampleBytes + 32;

   header.fmtID[0]  = 'f';
   header.fmtID[1]  = 'm';
   header.fmtID[2]  = 't';
   header.fmtID[3]  = ' ';
   header.formatChunkLen = 16;
   header.formatTag      = 1;
   header.channels       = channels;
   header.sampleRate     = rate;
   header.bitsPerSample  = SAMPLE_SIZE(int16Sample) * 8;
   header.blockAlign     = header.bitsPerSample * header.channels;
   header.avgBytesPerSec = header.sampleRate * header.blockAlign;

   header.dataID[0] = 'd';
   header.dataID[1] = 'a';
   header.dataID[2] = 't';
   header.dataID[3] = 'a';
   header.dataLen   = sampleBytes;

   FILE *pipe = popen(command.c_str(), "w");

   /* write the header */

   fwrite( &header, sizeof(wav_header), 1, pipe );

   //sampleCount maxSamples = int (timeStep * rate + 0.5);

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;
   bool cancelling = false;

   double t = t0;

   while (t < t1 && !cancelling) {

      double deltat = timeStep;
      if (t + deltat > t1)
         deltat = t1 - t;

      sampleCount numSamples = int (deltat * rate + 0.5);

      Mixer *mixer = new Mixer(channels, numSamples, true, rate, int16Sample);
      wxASSERT(mixer);
      mixer->Clear();

      char *buffer = new char[numSamples * SAMPLE_SIZE(int16Sample) * channels];
      wxASSERT(buffer);

      TrackListIterator iter(tracks);
      VTrack *tr = iter.First();
      while (tr) {
         if (tr->GetKind() == VTrack::Wave) {
            if (tr->GetSelected() || !selectionOnly) {
               if (tr->GetChannel() == VTrack::MonoChannel)
                  mixer->MixMono((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::LeftChannel)
                  mixer->MixLeft((WaveTrack *) tr, t, t + deltat);
               if (tr->GetChannel() == VTrack::RightChannel)
                  mixer->MixRight((WaveTrack *) tr, t, t + deltat);
            }
         }
         tr = iter.Next();
      }

      samplePtr mixed = mixer->GetBuffer();

      // Byte-swapping is neccesary on big-endian machines, since
      // WAV files are little-endian
#if wxBYTE_ORDER == wxBIG_ENDIAN
      {
         short *buffer = (short*)mixed;
         for( int i = 0; i < numSamples; i++ )
            buffer[i] = wxINT16_SWAP_ON_BE(buffer[i]);
      }
#endif

      fwrite( mixed, numSamples * channels * SAMPLE_SIZE(int16Sample), 1, pipe );

      t += deltat;

      if (!progress && wxGetElapsedTime(false) > 500) {

         wxString message;

         if (selectionOnly)
            message = "Exporting the selected audio using command-line encoder";
         else
            message = "Exporting the entire project using command-line encoder";

         progress =
             new wxProgressDialog("Export",
                                  message,
                                  1000,
                                  parent,
                                  wxPD_CAN_ABORT |
                                  wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
      }
      if (progress) {
         cancelling =
             !progress->Update(int (((t - t0) * 1000) / (t1 - t0) + 0.5));
      }

      delete mixer;
      delete[]buffer;
   }

   pclose( pipe );

   if(progress)
      delete progress;
   return true;
}
Beispiel #18
0
bool MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
                  double rate, sampleFormat format,
                  double startTime, double endTime,
                  WaveTrack **newLeft, WaveTrack **newRight)
{
   // This function was formerly known as "Quick Mix".  It takes one or
   // more tracks as input; of all tracks that are selected, it mixes
   // them together, applying any envelopes, amplitude gain, panning,
   // and real-time effects in the process.  The resulting pair of
   // tracks (stereo) are "rendered" and have no effects, gain, panning,
   // or envelopes.

   WaveTrack **waveArray;
   Track *t;
   int numWaves = 0;
   int numMono = 0;
   bool mono = false;
   int w;

   TrackListIterator iter(tracks);

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         numWaves++;
         float pan = ((WaveTrack*)t)->GetPan();
         if (t->GetChannel() == Track::MonoChannel && pan == 0)
            numMono++;
      }
      t = iter.Next();
   }

   if (numMono == numWaves)
      mono = true;

   double totalTime = 0.0;

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         if (t->GetEndTime() > totalTime)
            totalTime = t->GetEndTime();
      }
      t = iter.Next();
   }

   WaveTrack *mixLeft = trackFactory->NewWaveTrack(format, rate);
   mixLeft->SetName(_("Mix"));
   WaveTrack *mixRight = 0;
   if (mono) {
      mixLeft->SetChannel(Track::MonoChannel);
   }
   else {
      mixRight = trackFactory->NewWaveTrack(format, rate);
      mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(Track::LeftChannel);
      mixRight->SetChannel(Track::RightChannel);
      mixLeft->SetLinked(true);
      mixRight->SetTeamed(true);
   }

   int maxBlockLen = mixLeft->GetIdealBlockSize();

   if (startTime == endTime) {
      startTime = 0.0;
      endTime = totalTime;
   }

   Mixer *mixer = new Mixer(numWaves, waveArray, tracks->GetTimeTrack(),
                            startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   wxYield();
   GetActiveProject()->ProgressShow(_NoAcc("&Mix and Render"),
                                    _("Mixing and rendering tracks"));
   wxBusyCursor busy;
   
   bool cancelling = false;
   while(!cancelling) {
      sampleCount blockLen = mixer->Process(maxBlockLen);

      if (blockLen == 0)
         break;

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      }
      else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      int progressvalue = int (1000 * (mixer->MixGetCurrentTime() / totalTime));
      cancelling = !GetActiveProject()->ProgressUpdate(progressvalue);
   }

   GetActiveProject()->ProgressHide();

   mixLeft->Flush();
   *newLeft = mixLeft;
   if (!mono) {
      mixRight->Flush();
      *newRight = mixRight;
   }

#if 0
   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

   // Note: these shouldn't be translated - they're for debugging
   // and profiling only.
   printf("      Tracks: %d\n", numWaves);
   printf("  Mix length: %f sec\n", totalTime);
   printf("Elapsed time: %f sec\n", elapsedTime);
   printf("Max number of tracks to mix in real time: %f\n", maxTracks);
#endif

   delete[] waveArray;
   delete mixer;

   return true;
}
Beispiel #19
0
bool ExportOGG(AudacityProject *project,
               bool stereo, wxString fName,
               bool selectionOnly, double t0, double t1)
{
    double    rate    = project->GetRate();
    wxWindow  *parent = project;
    TrackList *tracks = project->GetTracks();
    double    quality = (gPrefs->Read("/FileFormats/OggExportQuality", 50)/(float)100.0);

    wxLogNull logNo;            // temporarily disable wxWindows error messages
    bool      cancelling = false;
    int       eos = 0;

    wxFFile outFile(fName, "wb");

    if(!outFile.IsOpened()) {
        wxMessageBox(_("Unable to open target file for writing"));
        return false;
    }

    // All the Ogg and Vorbis encoding data
    ogg_stream_state stream;
    ogg_page         page;
    ogg_packet       packet;

    vorbis_info      info;
    vorbis_comment   comment;
    vorbis_dsp_state dsp;
    vorbis_block     block;

    // Encoding setup
    vorbis_info_init(&info);
    vorbis_encode_init_vbr(&info, stereo ? 2 : 1, int(rate + 0.5), quality);

    vorbis_comment_init(&comment);
    // If we wanted to add comments, we would do it here

    // Set up analysis state and auxiliary encoding storage
    vorbis_analysis_init(&dsp, &info);
    vorbis_block_init(&dsp, &block);

    // Set up packet->stream encoder.  According to encoder example,
    // a random serial number makes it more likely that you can make
    // chained streams with concatenation.
    srand(time(NULL));
    ogg_stream_init(&stream, rand());

    // First we need to write the required headers:
    //    1. The Ogg bitstream header, which contains codec setup params
    //    2. The Vorbis comment header
    //    3. The bitstream codebook.
    //
    // After we create those our responsibility is complete, libvorbis will
    // take care of any other ogg bistream constraints (again, according
    // to the example encoder source)
    ogg_packet bitstream_header;
    ogg_packet comment_header;
    ogg_packet codebook_header;

    vorbis_analysis_headerout(&dsp, &comment, &bitstream_header, &comment_header,
                              &codebook_header);

    // Place these headers into the stream
    ogg_stream_packetin(&stream, &bitstream_header);
    ogg_stream_packetin(&stream, &comment_header);
    ogg_stream_packetin(&stream, &codebook_header);

    // Flushing these headers now guarentees that audio data will
    // start on a new page, which apparently makes streaming easier
    while(ogg_stream_flush(&stream, &page))
    {
        outFile.Write(page.header, page.header_len);
        outFile.Write(page.body, page.body_len);
    }

    wxProgressDialog *progress = NULL;

    wxYield();
    wxStartTimer();

    int numWaveTracks;
    WaveTrack **waveTracks;
    tracks->GetWaveTracks(selectionOnly, &numWaveTracks, &waveTracks);
    Mixer *mixer = new Mixer(numWaveTracks, waveTracks,
                             tracks->GetTimeTrack(),
                             t0, t1,
                             stereo? 2: 1, SAMPLES_PER_RUN, false,
                             rate, floatSample);

    while(!cancelling && !eos) {
        float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN);
        sampleCount samplesThisRun = mixer->Process(SAMPLES_PER_RUN);

        if (samplesThisRun == 0) {
            // Tell the library that we wrote 0 bytes - signalling the end.
            vorbis_analysis_wrote(&dsp, 0);
        }
        else {

            float *left = (float *)mixer->GetBuffer(0);
            memcpy(vorbis_buffer[0], left, sizeof(float)*SAMPLES_PER_RUN);

            if(stereo) {
                float *right = (float *)mixer->GetBuffer(1);
                memcpy(vorbis_buffer[1], right, sizeof(float)*SAMPLES_PER_RUN);
            }

            // tell the encoder how many samples we have
            vorbis_analysis_wrote(&dsp, samplesThisRun);
        }

        // I don't understand what this call does, so here is the comment
        // from the example, verbatim:
        //
        //    vorbis does some data preanalysis, then divvies up blocks
        //    for more involved (potentially parallel) processing. Get
        //    a single block for encoding now
        while(vorbis_analysis_blockout(&dsp, &block) == 1) {

            // analysis, assume we want to use bitrate management
            vorbis_analysis(&block, NULL);
            vorbis_bitrate_addblock(&block);

            while(vorbis_bitrate_flushpacket(&dsp, &packet)) {

                // add the packet to the bitstream
                ogg_stream_packetin(&stream, &packet);

                // From vorbis-tools-1.0/oggenc/encode.c:
                //   If we've gone over a page boundary, we can do actual output,
                //   so do so (for however many pages are available).

                while (!eos) {
                    int result = ogg_stream_pageout(&stream, &page);
                    if (!result)
                        break;

                    outFile.Write(page.header, page.header_len);
                    outFile.Write(page.body, page.body_len);

                    if (ogg_page_eos(&page))
                        eos = 1;
                }
            }
        }

        if(progress) {
            int progressvalue = int (1000 * ((mixer->MixGetCurrentTime()-t0) /
                                             (t1-t0)));
            cancelling = !progress->Update(progressvalue);
        }
        else if(wxGetElapsedTime(false) > 500) {

            wxString message = selectionOnly ?
                               _("Exporting the selected audio as Ogg Vorbis") :
                               _("Exporting the entire project as Ogg Vorbis");

            progress = new wxProgressDialog(
                _("Export"),
                message,
                1000,
                parent,
                wxPD_CAN_ABORT | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE);
        }
    }

    delete mixer;

    ogg_stream_clear(&stream);

    vorbis_block_clear(&block);
    vorbis_dsp_clear(&dsp);
    vorbis_info_clear(&info);

    outFile.Close();

    if(progress)
        delete progress;

    return true;
}
Beispiel #20
0
bool QuickMix(TrackList *tracks, DirManager *dirManager,
              double rate, sampleFormat format)
{
   WaveTrack **waveArray;
   VTrack *t;
   int numWaves = 0;
   int numLeft = 0;
   int numRight = 0;
   int numMono = 0;
   bool mono = false;
   int w;

   TrackListIterator iter(tracks);

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == VTrack::Wave) {
         numWaves++;
         switch (t->GetChannel()) {
         case VTrack::MonoChannel:
            numLeft++;
            numRight++;
            numMono++;
            break;
         case VTrack::LeftChannel:
            numLeft++;
            break;
         case VTrack::RightChannel:
            numRight++;
            break;
         }
      }
      t = iter.Next();
   }

   if (numMono == numWaves || numLeft == numWaves || numRight == numWaves)
      mono = true;

   double totalTime = 0.0;

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == VTrack::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         if (t->GetMaxLen() > totalTime)
            totalTime = t->GetMaxLen();
      }
      t = iter.Next();
   }

   WaveTrack *mixLeft = new WaveTrack(dirManager);
   mixLeft->SetSampleFormat(format);
   mixLeft->SetRate(rate);
   mixLeft->SetChannel(VTrack::MonoChannel);
   mixLeft->SetName(_("Mix"));
   WaveTrack *mixRight = 0;
   if (!mono) {
      mixRight = new WaveTrack(dirManager);
      mixRight->SetSampleFormat(format);
      mixRight->SetRate(rate);
      mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(VTrack::LeftChannel);
      mixRight->SetChannel(VTrack::RightChannel);
      mixLeft->SetLinked(true);
   }

   int maxBlockLen = mixLeft->GetIdealBlockSize();
   double maxBlockTime = maxBlockLen / mixLeft->GetRate();

   Mixer *mixer = new Mixer(mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;

   double tt = 0.0;
   while (tt < totalTime) {

      double blockTime = maxBlockTime;
      if (tt + blockTime > totalTime)
         blockTime = totalTime - tt;
      int blockLen = int (blockTime * mixLeft->GetRate());

      mixer->Clear();

      for (int i = 0; i < numWaves; i++) {
         if (mono)
            mixer->MixMono(waveArray[i], tt, tt + blockTime);
         else {
            switch (waveArray[i]->GetChannel()) {
            case VTrack::LeftChannel:
               mixer->MixLeft(waveArray[i], tt, tt + blockTime);
               break;
            case VTrack::RightChannel:
               mixer->MixRight(waveArray[i], tt, tt + blockTime);
               break;
            case VTrack::MonoChannel:
               mixer->MixMono(waveArray[i], tt, tt + blockTime);
               break;
            }
         }
      }

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      } else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      tt += blockTime;

      if (!progress && wxGetElapsedTime(false) > 500) {
         progress =
             new wxProgressDialog(_("Quick Mix"), _("Mixing tracks"), 1000);
      }
      if (progress) {
         int progressvalue = int (1000 * (tt / totalTime));
         progress->Update(progressvalue);
      }
   }

   tracks->Add(mixLeft);
   if (!mono)
      tracks->Add(mixRight);

   delete progress;

   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

#ifdef __WXGTK__
   printf(_("      Tracks: %d\n"), numWaves);
   printf(_("  Mix length: %f sec\n"), totalTime);
   printf(_("Elapsed time: %f sec\n"), elapsedTime);
   printf(_("Max number of tracks to mix in real time: %f\n"), maxTracks);
#endif

   delete waveArray;
   delete mixer;

   return true;
}
Beispiel #21
0
bool ImportWAV(wxString fName, WaveTrack **dest1, WaveTrack **dest2, DirManager *dirManager)
{
  *dest1 = 0;
  *dest2 = 0;

  snd_node sndfile;
  snd_node sndbuffer;
  
  sndfile.device = SND_DEVICE_FILE;
  sndfile.write_flag = SND_READ;
  strcpy(sndfile.u.file.filename, (const char *)fName);
  sndfile.u.file.file = 0;
  
  int err;
  long flags=0;
  
  err = snd_open(&sndfile, &flags);
  if (err) return false;
  
  if (sndfile.format.channels < 1 || sndfile.format.channels > 2)
  {
    wxMessageBox("Unknown audio format.");
	  return false;
  }

  *dest1 = new WaveTrack(dirManager);
  wxASSERT(*dest1);
  (*dest1)->rate = sndfile.format.srate;
  if (sndfile.format.channels == 2) {
    *dest2 = new WaveTrack(dirManager);
    wxASSERT(*dest1);
    (*dest2)->rate = sndfile.format.srate;
  }

  sndbuffer.device = SND_DEVICE_MEM;
  sndbuffer.write_flag = SND_WRITE;
  sndbuffer.u.mem.buffer_max = 0;
  sndbuffer.u.mem.buffer = 0;
  sndbuffer.u.mem.buffer_len = 0;
  sndbuffer.u.mem.buffer_pos = 0;
  sndbuffer.format.channels = sndfile.format.channels;
  sndbuffer.format.mode = SND_MODE_PCM; // SND_MODE_FLOAT
  sndbuffer.format.bits = 16;
  sndbuffer.format.srate = sndfile.format.srate;

  int maxblocksize = WaveTrack::GetIdealBlockSize();

  char *srcbuffer = new char[maxblocksize*2];
  char *dstbuffer = new char[maxblocksize*2];
  char *leftbuffer = new char[maxblocksize*2];
  char *rightbuffer = new char[maxblocksize*2];

  long filelen = sndfile.u.file.end_offset - sndfile.u.file.byte_offset;
  long bytescompleted = 0;

  wxProgressDialog *progress = NULL;  
  wxYield();
  wxStartTimer();
  wxBusyCursor busy;

  long block;
  do {
    block = maxblocksize;
    block = snd_read(&sndfile, srcbuffer, block);
    if (block > 0) {
      long b2 = snd_convert(&sndbuffer, dstbuffer,  // to
			    &sndfile, srcbuffer, block);      // from
      if (sndfile.format.channels == 1)
	(*dest1)->Append((sampleType *)dstbuffer, b2);
      else {
	for(int i=0; i<b2; i++) {
	  ((sampleType *)leftbuffer)[i] = ((sampleType *)dstbuffer)[2*i];
	  ((sampleType *)rightbuffer)[i] = ((sampleType *)dstbuffer)[2*i+1];
	}
	(*dest1)->Append((sampleType *)leftbuffer, (sampleCount)b2);
	(*dest2)->Append((sampleType *)rightbuffer, (sampleCount)b2);
      }
      
      bytescompleted += block;
      
    }
    
	if (!progress && wxGetElapsedTime(false) > 500) {
	  progress =
		new wxProgressDialog("Import","Importing audio file",
							 filelen);
	}	
	if (progress) {
	  int progressvalue = (bytescompleted > filelen)? filelen : bytescompleted;
	  progress->Update(progressvalue);
	}
  } while (block > 0);

  snd_close(&sndfile);

  #ifndef __WXMAC__
  if (bytescompleted != filelen) {
	printf("Bytes completed: %d   Expected file len: %d\n",
		   bytescompleted, filelen);
  }
  #endif

  if (progress)
	delete progress;
  
  delete[] srcbuffer;
  delete[] dstbuffer;
  delete[] leftbuffer;
  delete[] rightbuffer;
  
  return true;
}