Exemple #1
0
void ControlToolBar::OnRecord(wxCommandEvent &evt)
{
   if (gAudioIO->IsBusy()) {
      mRecord->PopUp();
      return;
   }
   AudacityProject *p = GetActiveProject();

   if( evt.GetInt() == 1 ) // used when called by keyboard shortcut. Default (0) ignored.
      mRecord->SetShift(true);
   if( evt.GetInt() == 2 )
      mRecord->SetShift(false);

   SetRecord(true, mRecord->WasShiftDown());

   if (p) {
      TrackList *t = p->GetTracks();
      TrackListIterator it(t);
      if(it.First() == NULL)
         mRecord->SetShift(false);
      double t0 = p->GetSel0();
      double t1 = p->GetSel1();
      if (t1 == t0)
         t1 = 1000000000.0;     // record for a long, long time (tens of years)

      /* TODO: set up stereo tracks if that is how the user has set up
       * their preferences, and choose sample format based on prefs */
      WaveTrackArray newRecordingTracks, playbackTracks;
#ifdef EXPERIMENTAL_MIDI_OUT
      NoteTrackArray midiTracks;
#endif
      bool duplex;
      gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);

      if(duplex){
         playbackTracks = t->GetWaveTrackArray(false);
#ifdef EXPERIMENTAL_MIDI_OUT
         midiTracks = t->GetNoteTrackArray(false);
#endif
     }
      else {
         playbackTracks = WaveTrackArray();
#ifdef EXPERIMENTAL_MIDI_OUT
         midiTracks = NoteTrackArray();
#endif
     }

      // If SHIFT key was down, the user wants append to tracks
      int recordingChannels = 0;
      bool shifted = mRecord->WasShiftDown();
      if (shifted) {
         bool sel = false;
         double allt0 = t0;

         // Find the maximum end time of selected and all wave tracks
         // Find whether any tracks were selected.  (If any are selected,
         // record only into them; else if tracks exist, record into all.)
         for (Track *tt = it.First(); tt; tt = it.Next()) {
            if (tt->GetKind() == Track::Wave) {
               WaveTrack *wt = static_cast<WaveTrack *>(tt);
               if (wt->GetEndTime() > allt0) {
                  allt0 = wt->GetEndTime();
               }

               if (tt->GetSelected()) {
                  sel = true;
                  if (wt->GetEndTime() > t0) {
                     t0 = wt->GetEndTime();
                  }
               }
            }
         }

         // Use end time of all wave tracks if none selected
         if (!sel) {
            t0 = allt0;
         }

         // Pad selected/all wave tracks to make them all the same length
         // Remove recording tracks from the list of tracks for duplex ("overdub")
         // playback.
         for (Track *tt = it.First(); tt; tt = it.Next()) {
            if (tt->GetKind() == Track::Wave && (tt->GetSelected() || !sel)) {
               WaveTrack *wt = static_cast<WaveTrack *>(tt);
               if (duplex)
                  playbackTracks.Remove(wt);
               t1 = wt->GetEndTime();
               if (t1 < t0) {
                  WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();
                  newTrack->InsertSilence(0.0, t0 - t1);
                  newTrack->Flush();
                  wt->Clear(t1, t0);
                  bool bResult = wt->Paste(t1, newTrack);
                  wxASSERT(bResult); // TO DO: Actually handle this.
                  delete newTrack;
               }
               newRecordingTracks.Add(wt);
            }
         }

         t1 = 1000000000.0;     // record for a long, long time (tens of years)
      }
      else {
         recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2);
         for (int c = 0; c < recordingChannels; c++) {
            WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();

            newTrack->SetOffset(t0);

            if (recordingChannels > 2)
              newTrack->SetMinimized(true);

            if (recordingChannels == 2) {
               if (c == 0) {
                  newTrack->SetChannel(Track::LeftChannel);
                  newTrack->SetLinked(true);
               }
               else {
                  newTrack->SetChannel(Track::RightChannel);
               }
            }
            else {
               newTrack->SetChannel( Track::MonoChannel );
            }

            newRecordingTracks.Add(newTrack);
         }

         // msmeyer: StartStream calls a callback which triggers auto-save, so
         // we add the tracks where recording is done into now. We remove them
         // later if starting the stream fails
         for (unsigned int i = 0; i < newRecordingTracks.GetCount(); i++)
            t->Add(newRecordingTracks[i]);
      }

      //Automated Input Level Adjustment Initialization
      #ifdef AUTOMATED_INPUT_LEVEL_ADJUSTMENT
         gAudioIO->AILAInitialize();
      #endif

      int token = gAudioIO->StartStream(playbackTracks,
                                        newRecordingTracks,
#ifdef EXPERIMENTAL_MIDI_OUT
                                        midiTracks,
#endif
                                        t->GetTimeTrack(),
                                        p->GetRate(), t0, t1, p);

      bool success = (token != 0);

      if (success) {
         p->SetAudioIOToken(token);
         mBusyProject = p;
      }
      else {
         // msmeyer: Delete recently added tracks if opening stream fails
         if (!shifted) {
            for (unsigned int i = 0; i < newRecordingTracks.GetCount(); i++) {
               t->Remove(newRecordingTracks[i]);
               delete newRecordingTracks[i];
            }
         }

         // msmeyer: Show error message if stream could not be opened
         wxMessageBox(_("Error while opening sound device. Please check the recording device settings and the project sample rate."),
                      _("Error"), wxOK | wxICON_EXCLAMATION, this);

         SetPlay(false);
         SetStop(false);
         SetRecord(false);
      }
   }
}
void ControlToolBar::OnRecord(wxCommandEvent &evt)
{
   if (gAudioIO->IsBusy()) {
      #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         if (mIsLocked) // Stop only if in locked mode. 
         {
            this->StopPlaying(); // Stop recording.
            mRecord->PopUp();
         }
         else
         {
            //v evt.GetClassInfo();
         }
      #else
         mRecord->PopUp();
      #endif
      return;
   }

   mPlay->Disable();
   #if (AUDACITY_BRANDING == BRAND_THINKLABS)
      mLoopPlay->Disable();
   #endif

   #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
      mStop->SetEnabled(mIsLocked);
   #else
      mStop->Enable();
   #endif
   mRewind->Disable();
   mFF->Disable();
   #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
      mPause->SetEnabled(mIsLocked);
      this->EnablePauseCommand(mIsLocked);
      this->SetRecord(mIsLocked); // If locked, push Record down, else up.
   #else
      mPause->Enable();
      mRecord->PushDown();
   #endif

   AudacityProject *p = GetActiveProject();
   if (p) {
      TrackList *t = p->GetTracks();

      // Don't do this for Audiotouch. Not necessary. The performance hit is in the track being recorded, below.
      #if (AUDACITY_BRANDING == BRAND_THINKLABS)
         // For versions that default to dual wave/spectrum display, 
         // switch all tracks to WaveformDisplay on Record, for performance.
         TrackListIterator iter(t);
         for (Track* pTrack = iter.First(); pTrack; pTrack = iter.Next())
            if (pTrack->GetKind() == Track::Wave)
               ((WaveTrack*)pTrack)->SetDisplay(WaveTrack::WaveformDisplay);
      #endif

      double t0 = p->GetSel0();
      double t1 = p->GetSel1();
      if (t1 == t0)
         t1 = 1000000000.0;     // record for a long, long time (tens of years)
      #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         if (p->m_bWantAppendRecording)
         {
            t0 = t->GetEndTime();
            t1 = 1000000000.0;     // record for a long, long time (tens of years)
         }
         gAudioIO->SetWantLatencyCorrection(!p->m_bWantAppendRecording);
      #endif

      /* TODO: set up stereo tracks if that is how the user has set up
       * their preferences, and choose sample format based on prefs */
      WaveTrackArray newRecordingTracks, playbackTracks;

      bool duplex;
      gPrefs->Read("/AudioIO/Duplex", &duplex, true);
      int recordingChannels = gPrefs->Read("/AudioIO/RecordChannels", 1);

      if( duplex )
         playbackTracks = t->GetWaveTrackArray(false);
      else
         playbackTracks = WaveTrackArray();

      for( int c = 0; c < recordingChannels; c++ )
      {
         WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();
         newTrack->SetOffset(t0);
         newTrack->SetRate(p->GetRate());

         //v for performance     newTrack->SetDisplay(WaveTrack::WaveformAndSpectrumDisplay);
         newTrack->SetDisplay(WaveTrack::WaveformDisplay); 
         
         if( recordingChannels == 2 )
         {
            if( c == 0 )
            {
               newTrack->SetChannel(Track::LeftChannel);
               newTrack->SetLinked(true);
            }
            else
               newTrack->SetChannel(Track::RightChannel);
         }
         else
         {
            newTrack->SetChannel( Track::MonoChannel );
         }

         newRecordingTracks.Add(newTrack);
      }

      int token = gAudioIO->StartStream(playbackTracks,
                                        newRecordingTracks, t->GetTimeTrack(),
                                        p->GetRate(), t0, t1);

      bool success = (token != 0);
      for( unsigned int i = 0; i < newRecordingTracks.GetCount(); i++ )
         if (success)
            t->Add(newRecordingTracks[i]);
         else
            delete newRecordingTracks[i];

      if (success) {
         p->SetAudioIOToken(token);
         mBusyProject = p;
         SetVUMeters(p);
         #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
            this->SetBackgroundColour(*wxRED); // red for Recording
            this->Refresh();
         #endif
      }
      else {
         // msmeyer: Show error message if stream could not be opened
         wxMessageBox(_("Error while opening sound device. Please check the input "
                        "device settings and the project sample rate."),
                      _("Error"), wxOK | wxICON_EXCLAMATION, this);

         SetPlay(false);
         #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
            mStop->Enable(); // In case it was disabled above, based on mIsLocked.
         #endif
         SetStop(false);
         SetRecord(false);
      }

      #if (AUDACITY_BRANDING == BRAND_AUDIOTOUCH)
         p->OnZoomFitV();
      #endif
   }
}
Exemple #3
0
//TODO-MB: wouldn't it make more sense to delete the time track after 'mix and render'?
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".
   WaveTrack **waveArray;
   Track *t;
   int numWaves = 0; /* number of wave tracks in the selection */
   int numMono = 0;  /* number of mono, centre-panned wave tracks in selection*/
   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) */
   int w;

   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

   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.

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();

   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         waveArray[w++] = (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)

   WaveTrack *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);
   WaveTrack *mixRight = 0;
   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 = new Mixer(numWaves, waveArray,
                            Mixer::WarpOptions(tracks->GetTimeTrack()),
                            startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   ::wxSafeYield();
   ProgressDialog *progress = new ProgressDialog(_("Mix and Render"),
                                                 _("Mixing and rendering tracks"));

   int updateResult = eProgressSuccess;
   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);
   }

   delete progress;

   mixLeft->Flush();
   if (!mono)
      mixRight->Flush();
   if (updateResult == eProgressCancelled || updateResult == eProgressFailed)
   {
      delete mixLeft;
      if (!mono)
         delete mixRight;
   } else {
      *newLeft = mixLeft;
      if (!mono)
         *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 (updateResult == eProgressSuccess || updateResult == eProgressStopped);
}
void ControlToolBar::OnRecord(wxCommandEvent &evt)
{
   if (gAudioIO->IsBusy()) {
      mRecord->PopUp();
      return;
   }
   AudacityProject *p = GetActiveProject();
   if (p && p->GetCleanSpeechMode()) {
      size_t numProjects = gAudacityProjects.Count();
      bool tracks = (p && !p->GetTracks()->IsEmpty());
      if (tracks || (numProjects > 1)) {
         wxMessageBox(_("Recording in CleanSpeech mode is not possible when a track, or more than one project, is already open."),
            _("Recording not permitted"),
            wxOK | wxICON_INFORMATION,
            this);
         mRecord->PopUp();
         mRecord->Disable();
         return;
      }
   }

   if( evt.GetInt() == 1 ) // used when called by keyboard shortcut. Default (0) ignored.
      mRecord->SetShift(true);
   if( evt.GetInt() == 2 )
      mRecord->SetShift(false);

   SetRecord(true);

   if (p) {
      TrackList *t = p->GetTracks();
      TrackListIterator it(t);
      if(it.First() == NULL)
         mRecord->SetShift(false);
      double t0 = p->GetSel0();
      double t1 = p->GetSel1();
      if (t1 == t0)
         t1 = 1000000000.0;     // record for a long, long time (tens of years)

      /* TODO: set up stereo tracks if that is how the user has set up
       * their preferences, and choose sample format based on prefs */
      WaveTrackArray newRecordingTracks, playbackTracks;
/* REQUIRES PORTMIDI */
//      NoteTrackArray midiTracks;

      bool duplex;
      gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true);
            
      if(duplex){
         playbackTracks = t->GetWaveTrackArray(false);
/* REQUIRES PORTMIDI */
//		 midiTracks = t->GetNoteTrackArray(false);
     }
      else {
         playbackTracks = WaveTrackArray();
/* REQUIRES PORTMIDI */
//		 midiTracks = NoteTrackArray();
     }
      
      // If SHIFT key was down, the user wants append to tracks
      int recordingChannels = 0;
      bool shifted = mRecord->WasShiftDown();
      if (shifted) {
         TrackListIterator it(t);
         WaveTrack *wt;
         bool sel = false;
         double allt0 = t0;

         // Find the maximum end time of selected and all wave tracks
         for (Track *tt = it.First(); tt; tt = it.Next()) {
            if (tt->GetKind() == Track::Wave) {
               wt = (WaveTrack *)tt;
               if (wt->GetEndTime() > allt0) {
                  allt0 = wt->GetEndTime();
               }
            
               if (tt->GetSelected()) {
                  sel = true;
                  if (duplex)
                     playbackTracks.Remove(wt);
                  if (wt->GetEndTime() > t0) {
                     t0 = wt->GetEndTime();
                  }
               }
            }
         }

         // Use end time of all wave tracks if none selected
         if (!sel) {
            t0 = allt0;
         }

         // Pad selected/all wave tracks to make them all the same length
         for (Track *tt = it.First(); tt; tt = it.Next()) {
            if (tt->GetKind() == Track::Wave && (tt->GetSelected() || !sel)) {
               wt = (WaveTrack *)tt;
               t1 = wt->GetEndTime();
               if (t1 < t0) {
                  WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();
                  newTrack->InsertSilence(0.0, t0 - t1);
                  newTrack->Flush();
                  wt->Clear(t1, t0);
                  wt->Paste(t1, newTrack);
                  delete newTrack;
               }
               newRecordingTracks.Add(wt);
            }
         }

         t1 = 1000000000.0;     // record for a long, long time (tens of years)
      }
      else {
         recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2);
         for (int c = 0; c < recordingChannels; c++) {
            WaveTrack *newTrack = p->GetTrackFactory()->NewWaveTrack();

            int initialheight = newTrack->GetHeight();

            newTrack->SetOffset(t0);

            if (recordingChannels <= 2) {
               newTrack->SetHeight(initialheight/recordingChannels);
            }
            else {
               newTrack->SetMinimized(true);
            }

            if (recordingChannels == 2) {
               if (c == 0) {
                  newTrack->SetChannel(Track::LeftChannel);
                  newTrack->SetLinked(true);
               }
               else {
                  newTrack->SetChannel(Track::RightChannel);
                  newTrack->SetTeamed(true);
               }
            }
            else {
               newTrack->SetChannel( Track::MonoChannel );
            }

            newRecordingTracks.Add(newTrack);
         }
         
         // msmeyer: StartStream calls a callback which triggers auto-save, so
         // we add the tracks where recording is done into now. We remove them
         // later if starting the stream fails
         for (unsigned int i = 0; i < newRecordingTracks.GetCount(); i++)
            t->Add(newRecordingTracks[i]);
      }

      int token = gAudioIO->StartStream(playbackTracks,
                                        newRecordingTracks,
/* REQUIRES PORTMIDI */
//                                        midiTracks,
                                        t->GetTimeTrack(),
                                        p->GetRate(), t0, t1, p);

      bool success = (token != 0);
      
      if (success) {
         p->SetAudioIOToken(token);
         mBusyProject = p;
         SetVUMeters(p);
      }
      else {
         // msmeyer: Delete recently added tracks if opening stream fails
         if (!shifted) {
            for (unsigned int i = 0; i < newRecordingTracks.GetCount(); i++) {
               t->Remove(newRecordingTracks[i]);
               delete newRecordingTracks[i];
            }
         }

         // msmeyer: Show error message if stream could not be opened
         wxMessageBox(_("Error while opening sound device. "
            wxT("Please check the input device settings and the project sample rate.")),
                      _("Error"), wxOK | wxICON_EXCLAMATION, this);

         SetPlay(false);
         SetStop(false);
         SetRecord(false);
      }
   }
}