bool LadspaEffect::Init() { mBlockSize = 0; mainRate = 0; TrackListIterator iter(mWaveTracks); Track *left = iter.First(); while(left) { if (mainRate == 0) mainRate = (int)(((WaveTrack *)left)->GetRate() + 0.5); if (left->GetLinked()) { Track *right = iter.Next(); if (((WaveTrack *)left)->GetRate() != ((WaveTrack *)right)->GetRate()) { wxMessageBox(_("Sorry, Plug-in Effects cannot be performed on stereo tracks where the individual channels of the track do not match.")); return false; } } left = iter.Next(); } if (mainRate<=0) mainRate = (int)(mProjectRate + 0.5); return true; }
bool BatchCommands::IsMono() { AudacityProject *project = GetActiveProject(); if( project == NULL ) { //wxMessageBox( wxT("No project and no Audio to process!") ); return false; } TrackList * tracks = project->GetTracks(); if( tracks == NULL ) { //wxMessageBox( wxT("No tracks to process!") ); return false; } TrackListIterator iter(tracks); Track *t = iter.First(); bool mono = true; while (t) { if (t->GetLinked()) { mono = false; break; } t = iter.Next(); } return mono; }
void ExportMultiple::CountTracksAndLabels() { mLabels = NULL; mNumLabels = 0; mNumWaveTracks = 0; Track* pTrack; for (pTrack = mIterator.First(mTracks); pTrack != NULL; pTrack = mIterator.Next()) { switch (pTrack->GetKind()) { // Count WaveTracks, and for linked pairs, count only the second of the pair. case Track::Wave: { if (pTrack->GetLinked() == false) mNumWaveTracks++; break; } case Track::Label: { // Supports only one LabelTrack. if (mLabels == NULL) { mLabels = (LabelTrack*)pTrack; mNumLabels = mLabels->GetNumLabels(); } break; } } } }
void ExportMultiple::CountTracksAndLabels() { mLabels = NULL; mNumLabels = 0; mNumWaveTracks = 0; Track* pTrack; for (pTrack = mIterator->First(mTracks); pTrack != NULL; pTrack = mIterator->Next()) { switch (pTrack->GetKind()) { // Count WaveTracks, and for linked pairs, count only the second of the pair. case Track::Wave: { if (!pTrack->GetMute() && !pTrack->GetLinked()) // Don't count muted tracks. mNumWaveTracks++; break; } // Only support one label track??? case Track::Label: { // Supports only one LabelTrack. if (mLabels == NULL) { mLabels = (LabelTrack*)pTrack; mNumLabels = mLabels->GetNumLabels(); } break; } } } }
int ExportMultiple::ShowModal() { Track *tr; mLabels = NULL; mNumLabels = 0; mNumTracks = 0; // Examine the track list looking for Wave and Label tracks for (tr = mIterator.First(mTracks); tr != NULL; tr = mIterator.Next()) { switch (tr->GetKind()) { // Only count WaveTracks, and for linked pairs, only count the // second one of the pair case Track::Wave: { if (tr->GetLinked() == false) { mNumTracks++; } break; } // Only support one label track??? case Track::Label: { if (mLabels == NULL) { mLabels = (LabelTrack *)tr; mNumLabels = mLabels->GetNumLabels(); } break; } } } if (mNumTracks < 2 && mNumLabels < 1) { ::wxMessageBox(_("If you have more than one Audio Track, you can export each track as a separate file,\nor if you have a Label Track, you can export a new file for each label.\n\nThis project does not have multiple tracks or a Label Track, so you cannot export multiple files."), _("Can't export multiple files"), wxOK | wxCENTRE, this); return wxID_CANCEL; } if (mNumLabels < 1) { mLabel->Enable(false); mTrack->SetValue(true); mLabel->SetValue(false); } if (mNumTracks < 2) { mTrack->Enable(false); mLabel->SetValue(true); mTrack->SetValue(false); } EnableControls(); return wxDialog::ShowModal(); }
bool LV2Effect::Process() { CopyInputTracks(); bool bGoodResult = true; TrackListIterator iter(mOutputTracks); int count = 0; Track *left = iter.First(); Track *right = NULL; while (left) { sampleCount lstart = 0, rstart = 0; sampleCount len; GetSamples((WaveTrack *)left, &lstart, &len); right = NULL; if (left->GetLinked() && mAudioInputs.GetCount() > 1) { right = iter.Next(); GetSamples((WaveTrack *)right, &rstart, &len); } if (mAudioInputs.GetCount() < 2 && right) { // If the effect is mono, apply to each channel separately bGoodResult = ProcessStereo(count, (WaveTrack *)left, NULL, lstart, 0, len) && ProcessStereo(count, (WaveTrack *)right, NULL, rstart, 0, len); } else { bGoodResult = ProcessStereo(count, (WaveTrack *)left, (WaveTrack *)right, lstart, rstart, len); } if (!bGoodResult) { break; } left = iter.Next(); count++; } ReplaceProcessedTracks(bGoodResult); return bGoodResult; }
bool Track::LinkConsistencyCheck() { // Sanity checks for linked tracks; unsetting the linked property // doesn't fix the problem, but it likely leaves us with orphaned // blockfiles instead of much worse problems. bool err = false; if (GetLinked()) { Track *l = GetLink(); if (l) { // A linked track's partner should never itself be linked if (l->GetLinked()) { wxLogWarning( wxT("Left track %s had linked right track %s with extra right track link.\n Removing extra link from right track."), GetName(), l->GetName()); err = true; l->SetLinked(false); } // Channels should be left and right if ( !( (GetChannel() == Track::LeftChannel && l->GetChannel() == Track::RightChannel) || (GetChannel() == Track::RightChannel && l->GetChannel() == Track::LeftChannel) ) ) { wxLogWarning( wxT("Track %s and %s had left/right track links out of order. Setting tracks to not be linked."), GetName(), l->GetName()); err = true; SetLinked(false); } } else { wxLogWarning( wxT("Track %s had link to NULL track. Setting it to not be linked."), GetName()); err = true; SetLinked(false); } } return ! err; }
bool LadspaEffect::Process() { this->CopyInputWaveTracks(); // Set up mOutputWaveTracks. bool bGoodResult = true; TrackListIterator iter(mOutputWaveTracks); int count = 0; Track *left = iter.First(); Track *right; while(left) { sampleCount lstart = 0, rstart = 0; sampleCount len; GetSamples((WaveTrack *)left, &lstart, &len); right = NULL; if (left->GetLinked() && inputs>1) { right = iter.Next(); GetSamples((WaveTrack *)right, &rstart, &len); } if (inputs < 2 && right) { // If the effect is mono, apply to each channel separately bGoodResult = ProcessStereo(count, (WaveTrack *)left, NULL, lstart, 0, len) && ProcessStereo(count, (WaveTrack *)right, NULL, rstart, 0, len); } else bGoodResult = ProcessStereo(count, (WaveTrack *)left, (WaveTrack *)right, lstart, rstart, len); if (!bGoodResult) break; left = iter.Next(); count++; } this->ReplaceProcessedWaveTracks(bGoodResult); return bGoodResult; }
bool LadspaEffect::Process() { TrackListIterator iter(mWaveTracks); int count = 0; Track *left = iter.First(); Track *right; while(left) { longSampleCount lstart, rstart; sampleCount len; GetSamples((WaveTrack *)left, &lstart, &len); right = NULL; if (left->GetLinked() && inputs>1) { right = iter.Next(); GetSamples((WaveTrack *)right, &rstart, &len); } bool success = false; if (inputs < 2 && right) { // If the effect is mono, apply to each channel separately success = ProcessStereo(count, (WaveTrack *)left, NULL, lstart, 0, len); if (success) success = ProcessStereo(count, (WaveTrack *)right, NULL, rstart, 0, len); } else success = ProcessStereo(count, (WaveTrack *)left, (WaveTrack *)right, lstart, rstart, len); if (!success) return false; left = iter.Next(); count++; } return true; }
void Effect::CountWaveTracks() { mNumTracks = 0; mNumGroups = 0; TrackListOfKindIterator iter(Track::Wave, mTracks); Track *t = iter.First(); while(t) { if (!t->GetSelected()) { t = iter.Next(); continue; } if (t->GetKind() == Track::Wave) { mNumTracks++; if (!t->GetLinked()) mNumGroups++; } t = iter.Next(); } }
void AudioIO::FillBuffers() { unsigned int numEmpty = 0; unsigned int i; // Playback buffers for(i=0; i<mNumOutBuffers; i++) { if (mOutBuffer[i].ID == 0) numEmpty++; } if (numEmpty > (mNumOutBuffers/2)) { sampleCount block = numEmpty * mBufferSize; double deltat = block / mRate; if (mT + deltat > mT1) { deltat = mT1 - mT; if(deltat < 0.0) return; block = (sampleCount)(deltat * mRate + 0.5); } Mixer *mixer = new Mixer(mNumOutChannels, block, true, mRate, mFormat); mixer->UseVolumeSlider(mProject->GetControlToolBar()); mixer->Clear(); TrackListIterator iter2(mTracks); int numSolo = 0; Track *vt = iter2.First(); while (vt) { if (vt->GetKind() == Track::Wave && vt->GetSolo()) numSolo++; vt = iter2.Next(); } TrackListIterator iter(mTracks); vt = iter.First(); while (vt) { if (vt->GetKind() == Track::Wave) { Track *mt = vt; // We want to extract mute and solo information from // the top of the two tracks if they're linked // (i.e. a stereo pair only has one set of mute/solo buttons) Track *partner = mTracks->GetLink(vt); if (partner && !vt->GetLinked()) mt = partner; else mt = vt; // Cut if somebody else is soloing if (numSolo>0 && !mt->GetSolo()) { vt = iter.Next(); continue; } // Cut if we're muted (unless we're soloing) if (mt->GetMute() && !mt->GetSolo()) { vt = iter.Next(); continue; } WaveTrack *t = (WaveTrack *) vt; switch (t->GetChannel()) { case Track::LeftChannel: mixer->MixLeft(t, mT, mT + deltat); break; case Track::RightChannel: mixer->MixRight(t, mT, mT + deltat); break; case Track::MonoChannel: mixer->MixMono(t, mT, mT + deltat); break; } } vt = iter.Next(); } // Copy the mixed samples into the buffers samplePtr outbytes = mixer->GetBuffer(); for(i=0; i<mNumOutBuffers && block>0; i++) if (mOutBuffer[i].ID == 0) { sampleCount count; if (block > mBufferSize) count = mBufferSize; else count = block; memcpy(mOutBuffer[i].data, outbytes, count*mNumOutChannels*SAMPLE_SIZE(mFormat)); block -= count; outbytes += (count*mNumOutChannels*SAMPLE_SIZE(mFormat)); mOutBuffer[i].len = count; mOutBuffer[i].ID = mOutID; mOutID++; } delete mixer; mT += deltat; } // Recording buffers unsigned int numFull = 0; unsigned int f, c; // loop counters sampleCount flatLen; for(i=0; i<mNumInBuffers; i++) { if (mInBuffer[i].ID != 0) numFull++; } if (numFull > 8) { samplePtr *flat = new samplePtr[mNumInChannels]; for(i=0; i<mNumInChannels; i++) flat[i] = NewSamples(numFull * mBufferSize, mFormat); flatLen = 0; for(f=0; f<numFull; f++) { int minID = mInID+1; int minIndex = 0; for(i=0; i<mNumInBuffers; i++) if (mInBuffer[i].ID > 0 && mInBuffer[i].ID < minID) { minIndex = i; minID = mInBuffer[i].ID; } switch(mFormat) { case floatSample: int j; for(j=0; j<mInBuffer[minIndex].len; j++) for(c=0; c<mNumInChannels; c++) { ((float *)flat[c])[flatLen+j] = ((float *)mInBuffer[minIndex].data)[j*mNumInChannels + c]; } break; default: wxASSERT(0); } flatLen += mInBuffer[minIndex].len; mInBuffer[minIndex].ID = 0; } for(i=0; i<mNumInChannels; i++) mInTracks[i]->Append(flat[i], mFormat, flatLen); for(i=0; i<mNumInChannels; i++) DeleteSamples(flat[i]); delete[] flat; mProject->RedrawProject(); } }
void LOFImportFileHandle::lofOpenFiles(wxString* ln) { wxStringTokenizer tok(*ln, wxT(" ")); wxStringTokenizer temptok1(*ln, wxT("\"")); wxStringTokenizer temptok2(*ln, wxT(" ")); int tokenplace = 0; wxString targetfile; wxString tokenholder = tok.GetNextToken(); if (tokenholder.IsSameAs(wxT("window"), false)) { // set any duration/offset factors for last window, as all files were called doDuration(); doScrollOffset(); if (windowCalledOnce) { mProject = CreateNewAudacityProject(gParentWindow); } windowCalledOnce = true; while (tok.HasMoreTokens()) { tokenholder = tok.GetNextToken(); if (tokenholder.IsSameAs(wxT("offset"), false)) { if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); if (Internat::CompatibleToDouble(tokenholder, &scrollOffset)) { callScrollOffset = true; } else { /* i18n-hint: You do not need to translate "LOF" */ wxMessageBox(_("Invalid window offset in LOF file."), /* i18n-hint: You do not need to translate "LOF" */ _("LOF Error"), wxOK | wxCENTRE, gParentWindow); } if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); } if (tokenholder.IsSameAs(wxT("duration"), false)) { if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); if (Internat::CompatibleToDouble(tokenholder, &durationFactor)) { callDurationFactor = true; } else { /* i18n-hint: You do not need to translate "LOF" */ wxMessageBox(_("Invalid duration in LOF file."), /* i18n-hint: You do not need to translate "LOF" */ _("LOF Error"), wxOK | wxCENTRE, gParentWindow); } } // End if statement if (tokenholder.IsSameAs(wxT("#"))) { // # indicates comments; ignore line tok = wxStringTokenizer(wxT(""), wxT(" ")); } } // End while loop } // End if statement else if (tokenholder.IsSameAs(wxT("file"), false)) { // To identify filename and open it tokenholder = temptok1.GetNextToken(); targetfile = temptok1.GetNextToken(); #ifdef USE_MIDI // If file is a midi if (targetfile.AfterLast(wxT('.')).IsSameAs(wxT("mid"), false) || targetfile.AfterLast(wxT('.')).IsSameAs(wxT("midi"), false)) { NoteTrack *nTrack = new NoteTrack(mProject->GetDirManager()); if (::ImportMIDI(targetfile, nTrack)) mProject->GetTracks()->Add(nTrack); else delete nTrack; } // If not a midi, open audio file else { #else // !USE_MIDI /* if we don't have midi support, go straight on to opening as an * audio file. TODO: Some sort of message here? */ { #endif // USE_MIDI mProject->OpenFile(targetfile); } // Set tok to right after filename temptok2.SetString(targetfile); tokenplace = temptok2.CountTokens(); for (int i = 0; i < tokenplace; i++) tokenholder = tok.GetNextToken(); if (tok.HasMoreTokens()) { tokenholder = tok.GetNextToken(); if (tokenholder.IsSameAs(wxT("#"))) { // # indicates comments; ignore line tok = wxStringTokenizer(wxT(""), wxT(" ")); } if (tokenholder.IsSameAs(wxT("offset"), false)) { if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); double offset; if (Internat::CompatibleToDouble(tokenholder, &offset)) { Track *t; TrackListIterator iter(mProject->GetTracks()); t = iter.First(); for (int i = 1; i < CountNumTracks(mProject) - 1; i++) t = iter.Next(); #ifdef USE_MIDI if (targetfile.AfterLast(wxT('.')).IsSameAs(wxT("mid"), false) || targetfile.AfterLast(wxT('.')).IsSameAs(wxT("midi"), false)) { wxMessageBox(_("MIDI tracks cannot be offset individually, only audio files can be."), _("LOF Error"), wxOK | wxCENTRE, gParentWindow); } else #endif { if (CountNumTracks(mProject) == 1) t->SetOffset(offset); else { if (t->GetLinked()) t->SetOffset(offset); t = iter.Next(); t->SetOffset(offset); } } } else { /* i18n-hint: You do not need to translate "LOF" */ wxMessageBox(_("Invalid track offset in LOF file."), _("LOF Error"), wxOK | wxCENTRE, gParentWindow); } } // End if statement } // End if statement } // End if statement else if (tokenholder.IsSameAs(wxT("#")))
/** @brief Processes a single line from a LOF text file, doing whatever is * indicated on the line. * * This function should just return for lines it cannot deal with, and the * caller will continue to the next line of the input file */ void LOFImportFileHandle::lofOpenFiles(wxString* ln) { wxStringTokenizer tok(*ln, wxT(" ")); wxStringTokenizer temptok1(*ln, wxT("\"")); wxStringTokenizer temptok2(*ln, wxT(" ")); int tokenplace = 0; wxString targetfile; wxString tokenholder = tok.GetNextToken(); if (tokenholder.IsSameAs(wxT("window"), false)) { // set any duration/offset factors for last window, as all files were called doDuration(); doScrollOffset(); if (windowCalledOnce) { mProject = CreateNewAudacityProject(); } windowCalledOnce = true; while (tok.HasMoreTokens()) { tokenholder = tok.GetNextToken(); if (tokenholder.IsSameAs(wxT("offset"), false)) { if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); if (Internat::CompatibleToDouble(tokenholder, &scrollOffset)) { callScrollOffset = true; } else { /* i18n-hint: You do not need to translate "LOF" */ wxMessageBox(_("Invalid window offset in LOF file."), /* i18n-hint: You do not need to translate "LOF" */ _("LOF Error"), wxOK | wxCENTRE); } if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); } if (tokenholder.IsSameAs(wxT("duration"), false)) { if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); if (Internat::CompatibleToDouble(tokenholder, &durationFactor)) { callDurationFactor = true; } else { /* i18n-hint: You do not need to translate "LOF" */ wxMessageBox(_("Invalid duration in LOF file."), /* i18n-hint: You do not need to translate "LOF" */ _("LOF Error"), wxOK | wxCENTRE); } } // End if statement if (tokenholder.IsSameAs(wxT("#"))) { // # indicates comments; ignore line tok = wxStringTokenizer(wxT(""), wxT(" ")); } } // End while loop } // End if statement handling "window" lines else if (tokenholder.IsSameAs(wxT("file"), false)) { // To identify filename and open it tokenholder = temptok1.GetNextToken(); targetfile = temptok1.GetNextToken(); // If path is relative, make absolute path from LOF path if(!wxIsAbsolutePath(targetfile)) { wxFileName fName(targetfile); fName.Normalize(wxPATH_NORM_ALL, mLOFFileName->GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR)); if(fName.FileExists()) { targetfile = fName.GetFullPath(); } } #ifdef USE_MIDI // If file is a midi if (targetfile.AfterLast(wxT('.')).IsSameAs(wxT("mid"), false) || targetfile.AfterLast(wxT('.')).IsSameAs(wxT("midi"), false)) { NoteTrack *nTrack = new NoteTrack(mProject->GetDirManager()); if (::ImportMIDI(targetfile, nTrack)) mProject->GetTracks()->Add(nTrack); else delete nTrack; } // If not a midi, open audio file else { #else // !USE_MIDI /* if we don't have midi support, go straight on to opening as an * audio file. TODO: Some sort of message here? */ { #endif // USE_MIDI mProject->OpenFile(targetfile); } // Set tok to right after filename temptok2.SetString(targetfile); tokenplace = temptok2.CountTokens(); for (int i = 0; i < tokenplace; i++) tokenholder = tok.GetNextToken(); if (tok.HasMoreTokens()) { tokenholder = tok.GetNextToken(); if (tokenholder.IsSameAs(wxT("#"))) { // # indicates comments; ignore line tok = wxStringTokenizer(wxT(""), wxT(" ")); } if (tokenholder.IsSameAs(wxT("offset"), false)) { if (tok.HasMoreTokens()) tokenholder = tok.GetNextToken(); double offset; // handle an "offset" specifier if (Internat::CompatibleToDouble(tokenholder, &offset)) { Track *t; TrackListIterator iter(mProject->GetTracks()); t = iter.First(); for (int i = 1; i < CountNumTracks(mProject) - 1; i++) t = iter.Next(); // t is now the last track in the project, unless the import of // all tracks failed, in which case it will be null. In that // case we return because we cannot offset a non-existent track. if (t == NULL) return; #ifdef USE_MIDI if (targetfile.AfterLast(wxT('.')).IsSameAs(wxT("mid"), false) || targetfile.AfterLast(wxT('.')).IsSameAs(wxT("midi"), false)) { wxMessageBox(_("MIDI tracks cannot be offset individually, only audio files can be."), _("LOF Error"), wxOK | wxCENTRE); } else #endif { if (CountNumTracks(mProject) == 1) t->SetOffset(offset); else { if (t->GetLinked()) t->SetOffset(offset); t = iter.Next(); t->SetOffset(offset); } } } // end of converting "offset" argument else { /* i18n-hint: You do not need to translate "LOF" */ wxMessageBox(_("Invalid track offset in LOF file."), _("LOF Error"), wxOK | wxCENTRE); } } // End if statement for "offset" parameters } // End if statement (more tokens after file name) } // End if statement "file" lines else if (tokenholder.IsSameAs(wxT("#")))
bool ScreenshotCommand::Apply(CommandExecutionContext context) { // Read the parameters that were passed in wxString filePath = GetString(wxT("FilePath")); wxString captureMode = GetString(wxT("CaptureMode")); wxString background = GetString(wxT("Background")); // Build a suitable filename wxString fileName = MakeFileName(filePath, captureMode); if (background.IsSameAs(wxT("Blue"))) { mBackground = true; mBackColor = wxColour(51, 102, 153); } else if (background.IsSameAs(wxT("White"))) { mBackground = true; mBackColor = wxColour(255, 255, 255); } else { mBackground = false; } // Reset the toolbars to a known state context.proj->mToolManager->Reset(); wxTopLevelWindow *w = GetFrontWindow(context.proj); if (!w) { return false; } if (captureMode.IsSameAs(wxT("window"))) { int x = 0, y = 0; int width, height; w->ClientToScreen(&x, &y); w->GetClientSize(&width, &height); if (w != context.proj && w->GetTitle() != wxT("")) { fileName = MakeFileName(filePath, captureMode + (wxT("-") + w->GetTitle() + wxT("-"))); } Capture(fileName, w, x, y, width, height); } else if (captureMode.IsSameAs(wxT("fullwindow")) || captureMode.IsSameAs(wxT("windowplus"))) { wxRect r = w->GetRect(); r.SetPosition(w->GetScreenPosition()); r = w->GetScreenRect(); if (w != context.proj && w->GetTitle() != wxT("")) { fileName = MakeFileName(filePath, captureMode + (wxT("-") + w->GetTitle() + wxT("-"))); } #if defined(__WXGTK__) // In wxGTK, we need to include decoration sizes r.width += (wxSystemSettings::GetMetric(wxSYS_BORDER_X, w) * 2); r.height += wxSystemSettings::GetMetric(wxSYS_CAPTION_Y, w) + wxSystemSettings::GetMetric(wxSYS_BORDER_Y, w); #endif if (!mBackground && captureMode.IsSameAs(wxT("windowplus"))) { // background colour not selected but we want a background wxRect b = GetBackgroundRect(); r.x = (r.x - b.x) >= 0 ? (r.x - b.x): 0; r.y = (r.y - b.y) >= 0 ? (r.y - b.y): 0; r.width += b.width; r.height += b.height; } Capture(fileName, w, r.x, r.y, r.width, r.height, true); } else if (captureMode.IsSameAs(wxT("fullscreen"))) { int width, height; wxDisplaySize(&width, &height); Capture(fileName, w, 0, 0, width, height); } else if (captureMode.IsSameAs(wxT("toolbars"))) { CaptureDock(context.proj->mToolManager->GetTopDock(), fileName); } else if (captureMode.IsSameAs(wxT("selectionbar"))) { CaptureDock(context.proj->mToolManager->GetBotDock(), fileName); } else if (captureMode.IsSameAs(wxT("tools"))) { CaptureToolbar(context.proj->mToolManager, ToolsBarID, fileName); } else if (captureMode.IsSameAs(wxT("control"))) { CaptureToolbar(context.proj->mToolManager, ControlBarID, fileName); } else if (captureMode.IsSameAs(wxT("mixer"))) { CaptureToolbar(context.proj->mToolManager, MixerBarID, fileName); } else if (captureMode.IsSameAs(wxT("meter"))) { CaptureToolbar(context.proj->mToolManager, MeterBarID, fileName); } else if (captureMode.IsSameAs(wxT("edit"))) { CaptureToolbar(context.proj->mToolManager, EditBarID, fileName); } else if (captureMode.IsSameAs(wxT("device"))) { CaptureToolbar(context.proj->mToolManager, DeviceBarID, fileName); } else if (captureMode.IsSameAs(wxT("transcription"))) { CaptureToolbar(context.proj->mToolManager, TranscriptionBarID, fileName); } else if (captureMode.IsSameAs(wxT("trackpanel"))) { TrackPanel *panel = context.proj->mTrackPanel; AdornedRulerPanel *ruler = panel->mRuler; int h = ruler->GetRulerHeight(); int x = 0, y = -h; int width, height; panel->ClientToScreen(&x, &y); panel->GetParent()->ScreenToClient(&x, &y); panel->GetClientSize(&width, &height); Capture(fileName, panel, x, y, width, height + h); } else if (captureMode.IsSameAs(wxT("ruler"))) { TrackPanel *panel = context.proj->mTrackPanel; AdornedRulerPanel *ruler = panel->mRuler; int x = 0, y = 0; int width, height; ruler->ClientToScreen(&x, &y); ruler->GetParent()->ScreenToClient(&x, &y); ruler->GetClientSize(&width, &height); height = ruler->GetRulerHeight(); Capture(fileName, ruler, x, y, width, height); } else if (captureMode.IsSameAs(wxT("tracks"))) { TrackPanel *panel = context.proj->mTrackPanel; int x = 0, y = 0; int width, height; panel->ClientToScreen(&x, &y); panel->GetParent()->ScreenToClient(&x, &y); panel->GetClientSize(&width, &height); Capture(fileName, panel, x, y, width, height); } else if (captureMode.IsSameAs(wxT("firsttrack"))) { TrackPanel *panel = context.proj->mTrackPanel; TrackListIterator iter(context.proj->GetTracks()); Track * t = iter.First(); if (!t) { return false; } wxRect r = panel->FindTrackRect(t, true); int x = 0, y = r.y - 3; int width, height; panel->ClientToScreen(&x, &y); panel->GetParent()->ScreenToClient(&x, &y); panel->GetClientSize(&width, &height); Capture(fileName, panel, x, y, width, r.height + 6); } else if (captureMode.IsSameAs(wxT("secondtrack"))) { TrackPanel *panel = context.proj->mTrackPanel; TrackListIterator iter(context.proj->GetTracks()); Track * t = iter.First(); if (!t) { return false; } if (t->GetLinked()) { t = iter.Next(); } t = iter.Next(); if (!t) { return false; } wxRect r = panel->FindTrackRect(t, true); int x = 0, y = r.y - 3; int width, height; panel->ClientToScreen(&x, &y); panel->GetParent()->ScreenToClient(&x, &y); panel->GetClientSize(&width, &height); Capture(fileName, panel, x, y, width, r.height + 6); } else { // Invalid capture mode! return false; } return true; }
void MixerBoard::UpdateTrackClusters() { if (mImageMuteUp == NULL) this->CreateMuteSoloImages(); const int nClusterHeight = mScrolledWindow->GetClientSize().GetHeight() - kDoubleInset; const size_t nClusterCount = mMixerTrackClusters.GetCount(); unsigned int nClusterIndex = 0; TrackListIterator iterTracks(mTracks); MixerTrackCluster* pMixerTrackCluster = NULL; Track* pLeftTrack; Track* pRightTrack; pLeftTrack = iterTracks.First(); while (pLeftTrack) { pRightTrack = pLeftTrack->GetLinked() ? iterTracks.Next() : NULL; if (pLeftTrack->GetKind() == Track::Wave) { if (nClusterIndex < nClusterCount) { // Already showing it. // Track clusters are maintained in the same order as the WaveTracks. // Track pointers can change for the "same" track for different states // on the undo stack, so update the pointers and display name. mMixerTrackClusters[nClusterIndex]->mLeftTrack = (WaveTrack*)pLeftTrack; mMixerTrackClusters[nClusterIndex]->mRightTrack = (WaveTrack*)pRightTrack; mMixerTrackClusters[nClusterIndex]->UpdateForStateChange(); } else { // Not already showing it. Add a new MixerTrackCluster. wxPoint clusterPos( (kInset + // extra inset to left for first one. (nClusterIndex * (kInset + kMixerTrackClusterWidth)) + // left margin and width for each to its left kInset), // plus left margin for new cluster kInset); wxSize clusterSize(kMixerTrackClusterWidth, nClusterHeight); pMixerTrackCluster = new MixerTrackCluster(mScrolledWindow, this, mProject, (WaveTrack*)pLeftTrack, (WaveTrack*)pRightTrack, clusterPos, clusterSize); if (pMixerTrackCluster) { mMixerTrackClusters.Add(pMixerTrackCluster); this->IncrementSoloCount((int)(pLeftTrack->GetSolo())); } } nClusterIndex++; } pLeftTrack = iterTracks.Next(); } if (pMixerTrackCluster) { // Added at least one MixerTrackCluster. this->UpdateWidth(); for (nClusterIndex = 0; nClusterIndex < mMixerTrackClusters.GetCount(); nClusterIndex++) mMixerTrackClusters[nClusterIndex]->HandleResize(); } else if (nClusterIndex < nClusterCount) { // We've got too many clusters. // This can only on things like Undo New Audio Track or Undo Import // that don't call RemoveTrackCluster explicitly. // We've already updated the track pointers for the clusters to the left, so just remove these. for (; nClusterIndex < nClusterCount; nClusterIndex++) this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mLeftTrack); } }
void ControlToolBar::OnRecord(wxCommandEvent &evt) { auto doubleClicked = mRecord->IsDoubleClicked(); mRecord->ClearDoubleClicked(); if (doubleClicked) { // Display a fixed recording head while scrolling the waves continuously. // If you overdub, you may want to anticipate some context in existing tracks, // so center the head. If not, put it rightmost to display as much wave as we can. const auto project = GetActiveProject(); bool duplex; gPrefs->Read(wxT("/AudioIO/Duplex"), &duplex, true); if (duplex) { // See if there is really anything being overdubbed if (gAudioIO->GetNumPlaybackChannels() == 0) // No. duplex = false; } using Mode = AudacityProject::PlaybackScroller::Mode; project->GetPlaybackScroller().Activate(duplex ? Mode::Centered : Mode::Right); return; } if (gAudioIO->IsBusy()) { if (!CanStopAudioStream() || 0 == gAudioIO->GetNumCaptureChannels()) mRecord->PopUp(); else mRecord->PushDown(); 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 *trackList = p->GetTracks(); TrackListIterator it(trackList); 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 = trackList->GetWaveTrackArray(false); #ifdef EXPERIMENTAL_MIDI_OUT midiTracks = trackList->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; TrackList tracksCopy{}; bool tracksCopied = false; 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) { auto end = playbackTracks.end(); auto it = std::find(playbackTracks.begin(), end, wt); if (it != end) playbackTracks.erase(it); } t1 = wt->GetEndTime(); if (t1 < t0) { if (!tracksCopied) { tracksCopied = true; tracksCopy = *trackList; } auto newTrack = p->GetTrackFactory()->NewWaveTrack(); newTrack->InsertSilence(0.0, t0 - t1); newTrack->Flush(); wt->Clear(t1, t0); bool bResult = wt->Paste(t1, newTrack.get()); wxASSERT(bResult); // TO DO: Actually handle this. wxUnusedVar(bResult); } newRecordingTracks.push_back(wt); } } t1 = 1000000000.0; // record for a long, long time (tens of years) } else { bool recordingNameCustom, useTrackNumber, useDateStamp, useTimeStamp; wxString defaultTrackName, defaultRecordingTrackName; int numTracks = 0; for (Track *tt = it.First(); tt; tt = it.Next()) { if (tt->GetKind() == Track::Wave && !tt->GetLinked()) numTracks++; } numTracks++; recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2); gPrefs->Read(wxT("/GUI/TrackNames/RecordingNameCustom"), &recordingNameCustom, false); gPrefs->Read(wxT("/GUI/TrackNames/TrackNumber"), &useTrackNumber, false); gPrefs->Read(wxT("/GUI/TrackNames/DateStamp"), &useDateStamp, false); gPrefs->Read(wxT("/GUI/TrackNames/TimeStamp"), &useTimeStamp, false); /* i18n-hint: The default name for an audio track. */ gPrefs->Read(wxT("/GUI/TrackNames/DefaultTrackName"),&defaultTrackName, _("Audio Track")); gPrefs->Read(wxT("/GUI/TrackNames/RecodingTrackName"), &defaultRecordingTrackName, defaultTrackName); wxString baseTrackName = recordingNameCustom? defaultRecordingTrackName : defaultTrackName; for (int c = 0; c < recordingChannels; c++) { auto newTrack = p->GetTrackFactory()->NewWaveTrack(); newTrack->SetOffset(t0); wxString nameSuffix = wxString(wxT("")); if (useTrackNumber) { nameSuffix += wxString::Format(wxT("%d"), numTracks + c); } if (useDateStamp) { if (!nameSuffix.IsEmpty()) { nameSuffix += wxT("_"); } nameSuffix += wxDateTime::Now().FormatISODate(); } if (useTimeStamp) { if (!nameSuffix.IsEmpty()) { nameSuffix += wxT("_"); } nameSuffix += wxDateTime::Now().FormatISOTime(); } // ISO standard would be nice, but ":" is unsafe for file name. nameSuffix.Replace(wxT(":"), wxT("-")); if (baseTrackName.IsEmpty()) { newTrack->SetName(nameSuffix); } else if (nameSuffix.IsEmpty()) { newTrack->SetName(baseTrackName); } else { newTrack->SetName(baseTrackName + wxT("_") + nameSuffix); } 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 ); } // Let the list hold the track, and keep a pointer to it newRecordingTracks.push_back( static_cast<WaveTrack*>( trackList->Add( std::move(newTrack)))); } } //Automated Input Level Adjustment Initialization #ifdef EXPERIMENTAL_AUTOMATED_INPUT_LEVEL_ADJUSTMENT gAudioIO->AILAInitialize(); #endif AudioIOStartStreamOptions options(p->GetDefaultPlayOptions()); int token = gAudioIO->StartStream(playbackTracks, newRecordingTracks, #ifdef EXPERIMENTAL_MIDI_OUT midiTracks, #endif t0, t1, options); bool success = (token != 0); if (success) { p->SetAudioIOToken(token); mBusyProject = p; } else { if (shifted) { // Restore the tracks to remove any inserted silence if (tracksCopied) *trackList = std::move(tracksCopy); } else { // msmeyer: Delete recently added tracks if opening stream fails for (unsigned int i = 0; i < newRecordingTracks.size(); i++) { trackList->Remove(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); } } UpdateStatusBar(GetActiveProject()); }
bool GetTrackInfoCommand::Apply(CommandExecutionContext context) { wxString mode = GetString(wxT("Type")); long trackIndex = GetLong(wxT("TrackIndex")); // Get the track indicated by the TrackIndex parameter // (Note: this ought to be somewhere else) long i = 0; TrackListIterator iter(context.proj->GetTracks()); Track *t = iter.First(); while (t && i != trackIndex) { t = iter.Next(); ++i; } if (i != trackIndex || !t) { Error(wxT("TrackIndex was invalid.")); return false; } // Now get the particular desired item about the track of interest if (mode.IsSameAs(wxT("Name"))) { Status(t->GetName()); } else if (mode.IsSameAs(wxT("StartTime"))) { Status(wxString::Format(wxT("%f"), t->GetStartTime())); } else if (mode.IsSameAs(wxT("EndTime"))) { Status(wxString::Format(wxT("%f"), t->GetEndTime())); } else if (mode.IsSameAs(wxT("Pan"))) { if(t->GetKind() == Track::Wave) Status(wxString::Format(wxT("%f"), static_cast<WaveTrack*>(t)->GetPan())); } else if (mode.IsSameAs(wxT("Gain"))) { if(t->GetKind() == Track::Wave) Status(wxString::Format(wxT("%f"), static_cast<WaveTrack*>(t)->GetGain())); } else if (mode.IsSameAs(wxT("Focused"))) { TrackPanel *panel = context.proj->GetTrackPanel(); SendBooleanStatus(panel->GetFocusedTrack() == t); } else if (mode.IsSameAs(wxT("Selected"))) { SendBooleanStatus(t->GetSelected()); } else if (mode.IsSameAs(wxT("Linked"))) { SendBooleanStatus(t->GetLinked()); } else if (mode.IsSameAs(wxT("Solo"))) { if (t->GetKind() == Track::Wave) SendBooleanStatus(t->GetSolo()); else SendBooleanStatus(false); } else if (mode.IsSameAs(wxT("Mute"))) { if (t->GetKind() == Track::Wave) SendBooleanStatus(t->GetMute()); else SendBooleanStatus(false); } else { Error(wxT("Invalid info type!")); return false; } return true; }