1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-11 06:31:07 +02:00
audacity/src/toolbars/ControlToolBar.cpp

1041 lines
28 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
ControlToolBar.cpp
Dominic Mazzoni
Shane T. Mueller
James Crook
Leland Lucius
*******************************************************************//**
\class ControlToolBar
\brief A ToolBar that has the main Transport buttons.
In the GUI, this is referred to as "Transport Toolbar", as
it corresponds to commands in the Transport menu.
"Control Toolbar" is historic.
This class, which is a child of Toolbar, creates the
window containing the Transport (rewind/play/stop/record/ff)
buttons. The window can be embedded within a
normal project window, or within a ToolbarFrame that is
managed by a global ToolBarStub called
gControlToolBarStub.
All of the controls in this window were custom-written for
Audacity - they are not native controls on any platform -
however, it is intended that the images could be easily
replaced to allow "skinning" or just customization to
match the look and feel of each platform.
*//*******************************************************************/
#include "../Audacity.h"
#include "../Experimental.h"
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/app.h>
#include <wx/dc.h>
#include <wx/event.h>
#include <wx/image.h>
#include <wx/intl.h>
#endif
#include <wx/tooltip.h>
#include "ControlToolBar.h"
#include "MeterToolBar.h"
#include "../AColor.h"
#include "../AllThemeResources.h"
#include "../AudioIO.h"
#include "../ImageManipulation.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../Theme.h"
#include "../Track.h"
#include "../widgets/AButton.h"
IMPLEMENT_CLASS(ControlToolBar, ToolBar);
//static
AudacityProject *ControlToolBar::mBusyProject = NULL;
////////////////////////////////////////////////////////////
/// Methods for ControlToolBar
////////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE(ControlToolBar, ToolBar)
EVT_CHAR(ControlToolBar::OnKeyEvent)
EVT_BUTTON(ID_PLAY_BUTTON, ControlToolBar::OnPlay)
EVT_BUTTON(ID_STOP_BUTTON, ControlToolBar::OnStop)
EVT_BUTTON(ID_RECORD_BUTTON, ControlToolBar::OnRecord)
EVT_BUTTON(ID_BATCH_BUTTON, ControlToolBar::OnBatch)
EVT_BUTTON(ID_REW_BUTTON, ControlToolBar::OnRewind)
EVT_BUTTON(ID_FF_BUTTON, ControlToolBar::OnFF)
EVT_BUTTON(ID_PAUSE_BUTTON, ControlToolBar::OnPause)
END_EVENT_TABLE()
//Standard constructor
// This was called "Control" toolbar in the GUI before - now it is "Transport".
// Note that we use the legacy "Control" string as the section because this
// gets written to prefs and cannot be changed in prefs to maintain backwards
// compatibility
ControlToolBar::ControlToolBar()
: ToolBar(TransportBarID, _("Transport"), wxT("Control"))
{
mPaused = false;
mSizer = NULL;
mCutPreviewTracks = NULL;
gPrefs->Read(wxT("/GUI/ErgonomicTransportButtons"), &mErgonomicTransportButtons, true);
gPrefs->Read(wxT("/Batch/CleanSpeechMode"), &mCleanSpeechMode, false);
}
ControlToolBar::~ControlToolBar()
{
wxTheApp->Disconnect( wxEVT_KEY_DOWN,
wxKeyEventHandler( ControlToolBar::OnKeyDown ),
NULL,
this );
wxTheApp->Disconnect( wxEVT_KEY_UP,
wxKeyEventHandler( ControlToolBar::OnKeyUp ),
NULL,
this );
}
void ControlToolBar::Create(wxWindow * parent)
{
ToolBar::Create(parent);
wxTheApp->Connect( wxEVT_KEY_DOWN,
wxKeyEventHandler( ControlToolBar::OnKeyDown ),
NULL,
this );
wxTheApp->Connect( wxEVT_KEY_UP,
wxKeyEventHandler( ControlToolBar::OnKeyUp ),
NULL,
this );
}
// This is a convenience function that allows for button creation in
// MakeButtons() with fewer arguments
AButton *ControlToolBar::MakeButton(teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled,
int id,
bool processdownevents,
const wxChar *label)
{
AButton *r = ToolBar::MakeButton(
bmpRecoloredUpLarge, bmpRecoloredDownLarge, bmpRecoloredHiliteLarge,
eEnabledUp, eEnabledDown, eDisabled,
wxWindowID(id),
wxDefaultPosition, processdownevents,
theTheme.ImageSize( bmpRecoloredUpLarge ));
r->SetLabel(label);
r->SetFocusRect( r->GetRect().Deflate( 12, 12 ) );
return r;
}
void ControlToolBar::MakeLoopImage()
{
// JKC: See ToolBar::MakeButton() for almost identical code. Condense??
wxSize Size1( theTheme.ImageSize( bmpRecoloredUpLarge ));
wxSize Size2( theTheme.ImageSize( bmpLoop ));
int xoff = (Size1.GetWidth() - Size2.GetWidth())/2;
int yoff = (Size1.GetHeight() - Size2.GetHeight())/2;
wxImage * up2 = OverlayImage(bmpRecoloredUpLarge, bmpLoop, xoff, yoff);
wxImage * hilite2 = OverlayImage(bmpRecoloredHiliteLarge, bmpLoop, xoff, yoff);
wxImage * down2 = OverlayImage(bmpRecoloredDownLarge, bmpLoop, xoff + 1, yoff + 1);
wxImage * disable2 = OverlayImage(bmpRecoloredUpLarge, bmpLoopDisabled, xoff, yoff);
mPlay->SetAlternateImages(*up2, *hilite2, *down2, *disable2);
delete up2;
delete hilite2;
delete down2;
delete disable2;
}
void ControlToolBar::Populate()
{
MakeButtonBackgroundsLarge();
mPause = MakeButton(bmpPause, bmpPause, bmpPauseDisabled,
ID_PAUSE_BUTTON, true, _("Pause"));
mPlay = MakeButton( bmpPlay, bmpPlay, bmpPlayDisabled,
ID_PLAY_BUTTON, true, _("Play"));
MakeLoopImage();
mStop = MakeButton( bmpStop, bmpStop, bmpStopDisabled ,
ID_STOP_BUTTON, false, _("Stop"));
mRewind = MakeButton(bmpRewind, bmpRewind, bmpRewindDisabled,
ID_REW_BUTTON, false, _("Start"));
mFF = MakeButton(bmpFFwd, bmpFFwd, bmpFFwdDisabled,
ID_FF_BUTTON, false, _("End"));
mRecord = MakeButton(bmpRecord, bmpRecord, bmpRecordDisabled,
ID_RECORD_BUTTON, true, _("Record"));
mBatch = MakeButton(bmpCleanSpeech, bmpCleanSpeech, bmpCleanSpeechDisabled,
ID_BATCH_BUTTON, false, _("Clean Speech"));
#if wxUSE_TOOLTIPS
RegenerateToolsTooltips();
wxToolTip::Enable(true);
wxToolTip::SetDelay(1000);
#endif
// Set default order and mode
ArrangeButtons();
}
void ControlToolBar::RegenerateToolsTooltips()
{
#if wxUSE_TOOLTIPS
mPause->SetToolTip(_("Pause"));
mPlay->SetToolTip(_("Play (Shift for Loop Play)"));
mStop->SetToolTip(_("Stop"));
mRewind->SetToolTip(_("Skip to Start"));
mFF->SetToolTip(_("Skip to End"));
mRecord->SetToolTip(_("Record (Shift for Append Record)"));
mBatch->SetToolTip(_("Clean Speech"));
#endif
}
void ControlToolBar::UpdatePrefs()
{
bool updated = false;
bool active;
RegenerateToolsTooltips();
gPrefs->Read( wxT("/GUI/ErgonomicTransportButtons"), &active, true );
if( mErgonomicTransportButtons != active )
{
mErgonomicTransportButtons = active;
updated = true;
}
gPrefs->Read( wxT("/Batch/CleanSpeechMode"), &active, false );
if( mCleanSpeechMode != active )
{
mCleanSpeechMode = active;
updated = true;
}
if( updated )
{
ReCreateButtons();
Updated();
}
// Set label to pull in language change
SetLabel(_("Transport"));
// Give base class a chance
ToolBar::UpdatePrefs();
}
void ControlToolBar::ArrangeButtons()
{
int flags = wxALIGN_CENTER | wxRIGHT;
// (Re)allocate the button sizer
if( mSizer )
{
Detach( mSizer );
delete mSizer;
}
mSizer = new wxBoxSizer( wxHORIZONTAL );
Add( mSizer, 1, wxEXPAND );
// Start with a little extra space
mSizer->Add( 5, 55 );
// Add the buttons in order based on ergonomic setting
if( mErgonomicTransportButtons )
{
mPause->MoveBeforeInTabOrder( mRecord );
mPlay->MoveBeforeInTabOrder( mRecord );
mStop->MoveBeforeInTabOrder( mRecord );
mRewind->MoveBeforeInTabOrder( mRecord );
mFF->MoveBeforeInTabOrder( mRecord );
mSizer->Add( mPause, 0, flags, 2 );
mSizer->Add( mPlay, 0, flags, 2 );
mSizer->Add( mStop, 0, flags, 2 );
mSizer->Add( mRewind, 0, flags, 2 );
mSizer->Add( mFF, 0, flags, 10 );
mSizer->Add( mRecord, 0, flags, 5 );
}
else
{
mRewind->MoveBeforeInTabOrder( mFF );
mPlay->MoveBeforeInTabOrder( mFF );
mRecord->MoveBeforeInTabOrder( mFF );
mPause->MoveBeforeInTabOrder( mFF );
mStop->MoveBeforeInTabOrder( mFF );
mSizer->Add( mRewind, 0, flags, 2 );
mSizer->Add( mPlay, 0, flags, 2 );
mSizer->Add( mRecord, 0, flags, 2 );
mSizer->Add( mPause, 0, flags, 2 );
mSizer->Add( mStop, 0, flags, 2 );
mSizer->Add( mFF, 0, flags, 5 );
}
// Add and possible hide the CleanSpeech button
mSizer->Add( mBatch, 0, flags | wxLEFT, 5 );
mSizer->Show( mBatch, mCleanSpeechMode );
// Layout the sizer
mSizer->Layout();
// Layout the toolbar
Layout();
// (Re)Establish the minimum size
SetMinSize( GetSizer()->GetMinSize() );
}
void ControlToolBar::ReCreateButtons()
{
// ToolBar::ReCreateButtons() will get rid of its sizer and
// since we've attached our sizer to it, ours will get deleted too
// so clean ours up first.
if( mSizer )
{
Detach( mSizer );
delete mSizer;
mSizer = NULL;
}
ToolBar::ReCreateButtons();
RegenerateToolsTooltips();
}
void ControlToolBar::Repaint( wxDC *dc )
{
#ifndef USE_AQUA_THEME
wxSize s = mSizer->GetSize();
wxPoint p = mSizer->GetPosition();
wxRect bevelRect( p.x, p.y, s.GetWidth() - 1, s.GetHeight() - 1 );
AColor::Bevel( *dc, true, bevelRect );
#endif
}
void ControlToolBar::EnableDisableButtons()
{
//TIDY-ME: Button logic could be neater.
AudacityProject *p = GetActiveProject();
size_t numProjects = gAudacityProjects.Count();
bool tracks = false;
bool cleaningSpeech = mBatch->IsDown();
bool playing = mPlay->IsDown();
bool recording = mRecord->IsDown();
bool busy = gAudioIO->IsBusy() || playing || recording;
// Only interested in audio type tracks
if (p) {
TrackListIterator iter( p->GetTracks() );
for (Track *t = iter.First(); t; t = iter.Next()) {
if (t->GetKind() == Track::Wave
#if defined(USE_MIDI)
|| t->GetKind() == Track::Note
#endif
) {
tracks = true;
break;
}
}
}
mPlay->SetEnabled((!recording) || (tracks && !busy && !cleaningSpeech));
mRecord->SetEnabled(!busy && !playing);
if (p && GetActiveProject()->GetCleanSpeechMode()) {
bool canRecord = !tracks;
canRecord &= !cleaningSpeech;
canRecord &= !busy;
canRecord &= ((numProjects == 0) || ((numProjects == 1) && !tracks));
mRecord->SetEnabled(canRecord);
mBatch->SetEnabled(!busy && !recording);
}
mStop->SetEnabled(busy && !cleaningSpeech);
mRewind->SetEnabled(tracks && !busy);
mFF->SetEnabled(tracks && !busy);
mPause->SetEnabled(true);
}
void ControlToolBar::SetPlay(bool down)
{
if (down)
mPlay->PushDown();
else {
mPlay->PopUp();
mPlay->SetAlternate(false);
}
EnableDisableButtons();
}
void ControlToolBar::SetStop(bool down)
{
if (down)
mStop->PushDown();
else {
if(FindFocus() == mStop)
mPlay->SetFocus();
mStop->PopUp();
}
EnableDisableButtons();
}
void ControlToolBar::SetRecord(bool down)
{
if (down)
mRecord->PushDown();
else {
mRecord->PopUp();
}
EnableDisableButtons();
}
bool ControlToolBar::IsRecordDown()
{
return mRecord->IsDown();
}
void ControlToolBar::PlayPlayRegion(double t0, double t1,
bool looped /* = false */,
bool cutpreview /* = false */,
TimeTrack *timetrack /* = NULL */)
{
SetPlay(true);
if (gAudioIO->IsBusy()) {
SetPlay(false);
return;
}
if (cutpreview && t0==t1) {
SetPlay(false);
return; /* msmeyer: makes no sense */
}
AudacityProject *p = GetActiveProject();
if (!p) {
SetPlay(false);
return; // Should never happen, but...
}
TrackList *t = p->GetTracks();
if (!t) {
mPlay->PopUp();
return; // Should never happen, but...
}
bool hasaudio = false;
TrackListIterator iter(t);
for (Track *trk = iter.First(); trk; trk = iter.Next()) {
if (trk->GetKind() == Track::Wave
#ifdef EXPERIMENTAL_MIDI_OUT
|| trk->GetKind() == Track::Note
#endif
) {
hasaudio = true;
break;
}
}
if (!hasaudio) {
SetPlay(false);
return; // No need to continue without audio tracks
}
double maxofmins,minofmaxs;
#if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
double init_seek = 0.0;
#endif
// JS: clarified how the final play region is computed;
if (t1 == t0) {
// msmeyer: When playing looped, we play the whole file, if
// no range is selected. Otherwise, we play from t0 to end
if (looped) {
// msmeyer: always play from start
t0 = t->GetStartTime();
} else {
// move t0 to valid range
if (t0 < 0) {
t0 = t->GetStartTime();
}
else if (t0 > t->GetEndTime()) {
t0 = t->GetEndTime();
}
#if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
else {
init_seek = t0; //AC: init_seek is where playback will 'start'
t0 = t->GetStartTime();
}
#endif
}
// always play to end
t1 = t->GetEndTime();
}
else {
// always t0 < t1 right?
// the set intersection between the play region and the
// valid range maximum of lower bounds
if (t0 < t->GetStartTime())
maxofmins = t->GetStartTime();
else
maxofmins = t0;
// minimum of upper bounds
if (t1 > t->GetEndTime())
minofmaxs = t->GetEndTime();
else
minofmaxs = t1;
// we test if the intersection has no volume
if (minofmaxs <= maxofmins) {
// no volume; play nothing
return;
}
else {
t0 = maxofmins;
t1 = minofmaxs;
}
}
// Can't play before 0...either shifted or latencey corrected tracks
if (t0 < 0.0) {
t0 = 0.0;
}
bool success = false;
if (t1 > t0) {
int token;
if (cutpreview) {
double beforeLen, afterLen;
gPrefs->Read(wxT("/AudioIO/CutPreviewBeforeLen"), &beforeLen, 1.0);
gPrefs->Read(wxT("/AudioIO/CutPreviewAfterLen"), &afterLen, 1.0);
double tcp0 = t0-beforeLen;
double tcp1 = (t1+afterLen) - (t1-t0);
SetupCutPreviewTracks(tcp0, t0, t1, tcp1);
if (mCutPreviewTracks)
{
token = gAudioIO->StartStream(
mCutPreviewTracks->GetWaveTrackArray(false),
WaveTrackArray(),
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrackArray(),
#endif
NULL, p->GetRate(), tcp0, tcp1, p, false,
t0, t1-t0);
} else
{
// Cannot create cut preview tracks, clean up and exit
SetPlay(false);
SetStop(false);
SetRecord(false);
return;
}
} else {
if (!timetrack) {
timetrack = t->GetTimeTrack();
}
token = gAudioIO->StartStream(t->GetWaveTrackArray(false),
WaveTrackArray(),
#ifdef EXPERIMENTAL_MIDI_OUT
t->GetNoteTrackArray(false),
#endif
timetrack,
p->GetRate(), t0, t1, p, looped);
}
if (token != 0) {
success = true;
p->SetAudioIOToken(token);
mBusyProject = p;
#if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
//AC: If init_seek was set, now's the time to make it happen.
gAudioIO->SeekStream(init_seek);
#endif
SetVUMeters(p);
}
else {
// msmeyer: Show error message if stream could not be opened
wxMessageBox(_(
"Error while opening sound device. "
wxT("Please check the output device settings and the project sample rate.")),
_("Error"), wxOK | wxICON_EXCLAMATION, this);
}
}
if (!success) {
SetPlay(false);
SetStop(false);
SetRecord(false);
}
}
void ControlToolBar::SetVUMeters(AudacityProject *p)
{
MeterToolBar *bar;
bar = p->GetMeterToolBar();
if (bar) {
Meter *play, *record;
bar->GetMeters(&play, &record);
gAudioIO->SetMeters(record, play);
}
}
void ControlToolBar::PlayCurrentRegion(bool looped /* = false */,
bool cutpreview /* = false */)
{
mPlay->SetAlternate(looped);
AudacityProject *p = GetActiveProject();
if (p)
{
if (looped)
p->mLastPlayMode = loopedPlay;
else
p->mLastPlayMode = normalPlay;
double playRegionStart, playRegionEnd;
p->GetPlayRegion(&playRegionStart, &playRegionEnd);
PlayPlayRegion(playRegionStart,
playRegionEnd,
looped, cutpreview);
}
}
void ControlToolBar::OnKeyEvent(wxKeyEvent & event)
{
if (event.ControlDown() || event.AltDown()) {
event.Skip();
return;
}
if (event.GetKeyCode() == WXK_SPACE) {
if (gAudioIO->IsStreamActive(GetActiveProject()->GetAudioIOToken())) {
SetPlay(false);
SetStop(true);
StopPlaying();
}
else if (!gAudioIO->IsBusy()) {
SetPlay(true);
SetStop(false);
PlayCurrentRegion();
}
return;
}
event.Skip();
}
void ControlToolBar::OnKeyDown(wxKeyEvent & event)
{
event.Skip();
if (event.GetKeyCode() == WXK_SHIFT ) {
// Turn the "Play" button into a "Loop" button
if (!mPlay->IsDown())
mPlay->SetAlternate(true);
}
}
void ControlToolBar::OnKeyUp(wxKeyEvent & event)
{
event.Skip();
if (event.GetKeyCode() == WXK_SHIFT ) {
// Turn the "Loop" button into a "Play" button
if (!mPlay->IsDown())
mPlay->SetAlternate(false);
}
}
void ControlToolBar::OnPlay(wxCommandEvent &evt)
{
StopPlaying();
AudacityProject *p = GetActiveProject();
if (p) p->TP_DisplaySelection();
PlayDefault();
}
void ControlToolBar::OnStop(wxCommandEvent &evt)
{
StopPlaying();
}
void ControlToolBar::PlayDefault()
{
if(mPlay->WasControlDown())
PlayCurrentRegion(false, true); /* play with cut preview */
else if(mPlay->WasShiftDown())
PlayCurrentRegion(true); /* play looped */
else
PlayCurrentRegion(false); /* play normal */
mPlay->PopUp();
}
void ControlToolBar::StopPlaying(bool stopStream /* = true*/)
{
mStop->PushDown();
SetStop(false);
if(stopStream)
gAudioIO->StopStream();
SetPlay(false);
SetRecord(false);
#ifdef AUTOMATED_INPUT_LEVEL_ADJUSTMENT
gAudioIO->AILADisable();
#endif
mPause->PopUp();
mPaused=false;
//Make sure you tell gAudioIO to unpause
gAudioIO->SetPaused(mPaused);
ClearCutPreviewTracks();
mBusyProject = NULL;
// So that we continue monitoring after playing or recording.
// also clean the MeterQueues
AudacityProject *project = GetActiveProject();
if( project ) {
project->MayStartMonitoring();
project->GetMeterToolBar()->Clear();
}
}
void ControlToolBar::OnBatch(wxCommandEvent &evt)
{
AudacityProject *proj = GetActiveProject();
proj->OnApplyChain();
mPlay->Enable();
mStop->Enable();
mRewind->Enable();
mFF->Enable();
mPause->Disable();
mBatch->Enable();
mBatch->PopUp();
}
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;
#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) {
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);
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;
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);
}
}
}
void ControlToolBar::OnPause(wxCommandEvent &evt)
{
if(mPaused)
{
mPause->PopUp();
mPaused=false;
}
else
{
mPause->PushDown();
mPaused=true;
}
gAudioIO->SetPaused(mPaused);
}
void ControlToolBar::OnRewind(wxCommandEvent &evt)
{
mRewind->PushDown();
mRewind->PopUp();
AudacityProject *p = GetActiveProject();
if (p) {
p->Rewind(mRewind->WasShiftDown());
}
}
void ControlToolBar::OnFF(wxCommandEvent &evt)
{
mFF->PushDown();
mFF->PopUp();
AudacityProject *p = GetActiveProject();
if (p) {
p->SkipEnd(mFF->WasShiftDown());
}
}
void ControlToolBar::SetupCutPreviewTracks(double playStart, double cutStart,
double cutEnd, double playEnd)
{
ClearCutPreviewTracks();
AudacityProject *p = GetActiveProject();
if (p) {
// Find first selected track (stereo or mono) and duplicate it
Track *track1 = NULL, *track2 = NULL;
TrackListIterator it(p->GetTracks());
for (Track *t = it.First(); t; t = it.Next())
{
if (t->GetKind() == Track::Wave && t->GetSelected())
{
track1 = t;
track2 = t->GetLink();
break;
}
}
if (track1)
{
// Duplicate and change tracks
track1 = track1->Duplicate();
track1->Clear(cutStart, cutEnd);
if (track2)
{
track2 = track2->Duplicate();
track2->Clear(cutStart, cutEnd);
}
mCutPreviewTracks = new TrackList();
mCutPreviewTracks->Add(track1);
if (track2)
mCutPreviewTracks->Add(track2);
}
}
}
void ControlToolBar::ClearCutPreviewTracks()
{
if (mCutPreviewTracks)
{
mCutPreviewTracks->Clear(true); /* delete track contents too */
delete mCutPreviewTracks;
mCutPreviewTracks = NULL;
}
}
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: ebfdc42a-6a03-4826-afa2-937a48c0565b