bool EffectRepeat::Process() { this->CopyInputWaveTracks(); // Set up mOutputWaveTracks. bool bGoodResult = true; TrackListIterator iter(mOutputWaveTracks); WaveTrack *track = (WaveTrack *) iter.First(); int nTrack = 0; double maxDestLen = 0.0; // used to change selection to generated bit while ((track != NULL) && bGoodResult) { double trackStart = track->GetStartTime(); double trackEnd = track->GetEndTime(); double t0 = mT0 < trackStart? trackStart: mT0; double t1 = mT1 > trackEnd? trackEnd: mT1; if (t1 <= t0) continue; sampleCount start = track->TimeToLongSamples(t0); sampleCount end = track->TimeToLongSamples(t1); sampleCount len = (sampleCount)(end - start); double tLen = track->LongSamplesToTime(len); double tc = t0 + tLen; if (len <= 0) continue; Track *dest; track->Copy(t0, t1, &dest); for(int j=0; j<repeatCount; j++) { if (!track->Paste(tc, dest) || TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. { bGoodResult = false; break; } tc += tLen; } if (tc > maxDestLen) maxDestLen = tc; delete dest; track = (WaveTrack *) iter.Next(); nTrack++; } if (bGoodResult) { // Change selection to just the generated bits. mT0 = mT1; mT1 = maxDestLen; } this->ReplaceProcessedWaveTracks(bGoodResult); return bGoodResult; }
bool EffectNoise::Process() { if (noiseDuration <= 0.0) noiseDuration = sDefaultGenerateLen; //Iterate over each track TrackListIterator iter(mWaveTracks); WaveTrack *track = (WaveTrack *)iter.First(); while (track) { WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate()); numSamples = (longSampleCount)(noiseDuration * track->GetRate() + 0.5); longSampleCount i = 0; float *data = new float[tmp->GetMaxBlockSize()]; sampleCount block; while(i < numSamples) { block = tmp->GetBestBlockSize(i); if (block > (numSamples - i)) block = numSamples - i; MakeNoise(data, block, track->GetRate(), noiseAmplitude); tmp->Append((samplePtr)data, floatSample, block); i += block; } delete[] data; tmp->Flush(); track->Clear(mT0, mT1); track->Paste(mT0, tmp); delete tmp; //Iterate to the next track track = (WaveTrack *)iter.Next(); } /* save last used values save duration unless value was got from selection, so we save only when user explicitely setup a value */ if (mT1 == mT0) gPrefs->Write(wxT("/CsPresets/NoiseGen_Duration"), noiseDuration); gPrefs->Write(wxT("/CsPresets/NoiseGen_Type"), noiseType); gPrefs->Write(wxT("/CsPresets/NoiseGen_Amp"), noiseAmplitude); mT1 = mT0 + noiseDuration; // Update selection. return true; }
bool EffectToneGen::Process() { if (length <= 0.0) length = sDefaultGenerateLen; //Iterate over each track TrackListIterator iter(mWaveTracks); WaveTrack *track = (WaveTrack *)iter.First(); while (track) { mSample = 0; WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat()); mCurRate = track->GetRate(); tmp->SetRate(mCurRate); longSampleCount numSamples = (longSampleCount)(length * mCurRate + 0.5); longSampleCount i = 0; float *data = new float[tmp->GetMaxBlockSize()]; sampleCount block; while(i < numSamples) { block = tmp->GetBestBlockSize(i); if (block > (numSamples - i)) block = numSamples - i; MakeTone(data, block); tmp->Append((samplePtr)data, floatSample, block); i += block; } delete[] data; tmp->Flush(); track->Clear(mT0, mT1); track->Paste(mT0, tmp); delete tmp; //Iterate to the next track track = (WaveTrack *)iter.Next(); } mT1 = mT0 + length; // Update selection. return true; }
VTrack *WaveTrack::Duplicate() { WaveTrack *copy = new WaveTrack(dirManager); copy->tOffset = tOffset; copy->rate = rate; copy->name = name; copy->linked = linked; copy->mute = mute; copy->solo = solo; copy->Paste(0.0, this); copy->collapsedHeight = collapsedHeight; copy->expandedHeight = expandedHeight; copy->channel = channel; copy->selected = selected; copy->envelope.CopyFrom(&envelope); copy->display = display; return (VTrack *) copy; }
bool EffectSilence::Process() { if (length <= 0.0) length = sDefaultGenerateLen; TrackListIterator iter(mWaveTracks); WaveTrack *track = (WaveTrack *)iter.First(); while (track) { WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate()); tmp->InsertSilence(0.0, length); tmp->Flush(); track->Clear(mT0, mT1); track->Paste(mT0, tmp); delete tmp; //Iterate to the next track track = (WaveTrack *)iter.Next(); } mT1 = mT0 + length; // Update selection. return true; }
bool EffectNoise::Process() { if (noiseDuration <= 0.0) noiseDuration = sDefaultGenerateLen; //Iterate over each track int ntrack = 0; this->CopyInputWaveTracks(); // Set up mOutputWaveTracks. bool bGoodResult = true; TrackListIterator iter(mOutputWaveTracks); WaveTrack *track = (WaveTrack *)iter.First(); while (track) { WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate()); numSamples = (longSampleCount)(noiseDuration * track->GetRate() + 0.5); longSampleCount i = 0; float *data = new float[tmp->GetMaxBlockSize()]; sampleCount block; while ((i < numSamples) && bGoodResult) { block = tmp->GetBestBlockSize(i); if (block > (numSamples - i)) block = numSamples - i; MakeNoise(data, block, track->GetRate(), noiseAmplitude); tmp->Append((samplePtr)data, floatSample, block); i += block; //Update the Progress meter if (TrackProgress(ntrack, (double)i / numSamples)) bGoodResult = false; } delete[] data; tmp->Flush(); track->Clear(mT0, mT1); track->Paste(mT0, tmp); delete tmp; if (!bGoodResult) break; //Iterate to the next track ntrack++; track = (WaveTrack *)iter.Next(); } if (bGoodResult) { /* save last used values save duration unless value was got from selection, so we save only when user explicitely setup a value */ if (mT1 == mT0) gPrefs->Write(wxT("/CsPresets/NoiseGen_Duration"), noiseDuration); gPrefs->Write(wxT("/CsPresets/NoiseGen_Type"), noiseType); gPrefs->Write(wxT("/CsPresets/NoiseGen_Amp"), noiseAmplitude); mT1 = mT0 + noiseDuration; // Update selection. } this->ReplaceProcessedWaveTracks(bGoodResult); return bGoodResult; }
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) { 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 EffectRepeat::Process() { // Set up mOutputTracks. // This effect needs Track::All for sync-lock grouping. CopyInputTracks(Track::All); int nTrack = 0; bool bGoodResult = true; double maxDestLen = 0.0; // used to change selection to generated bit TrackListIterator iter(mOutputTracks); for (Track *t = iter.First(); t && bGoodResult; t = iter.Next()) { if (t->GetKind() == Track::Label) { if (t->GetSelected() || t->IsSyncLockSelected()) { LabelTrack* track = (LabelTrack*)t; if (!track->Repeat(mT0, mT1, repeatCount)) { bGoodResult = false; break; } } } else if (t->GetKind() == Track::Wave && t->GetSelected()) { WaveTrack* track = (WaveTrack*)t; sampleCount start = track->TimeToLongSamples(mT0); sampleCount end = track->TimeToLongSamples(mT1); sampleCount len = (sampleCount)(end - start); double tLen = track->LongSamplesToTime(len); double tc = mT0 + tLen; if (len <= 0) { continue; } auto dest = track->Copy(mT0, mT1); for(int j=0; j<repeatCount; j++) { if (!track->Paste(tc, dest.get()) || TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel. { bGoodResult = false; break; } tc += tLen; } if (tc > maxDestLen) maxDestLen = tc; nTrack++; } else if (t->IsSyncLockSelected()) { t->SyncLockAdjust(mT1, mT1 + (mT1 - mT0) * repeatCount); } } if (bGoodResult) { // Select the NEW bits + original bit mT1 = maxDestLen; } ReplaceProcessedTracks(bGoodResult); return bGoodResult; }
bool EffectDtmf::Process() { if (dtmfDuration <= 0.0) return false; //Iterate over each track TrackListIterator iter(mWaveTracks); WaveTrack *track = (WaveTrack *)iter.First(); while (track) { // new tmp track, to fill with dtmf sequence // we will build the track by adding a tone, then a silence, next tone, and so on... WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate()); // all dtmf sequence durations in samples from seconds numSamplesSequence = (longSampleCount)(dtmfDuration * track->GetRate() + 0.5); numSamplesTone = (longSampleCount)(dtmfTone * track->GetRate() + 0.5); numSamplesSilence = (longSampleCount)(dtmfSilence * track->GetRate() + 0.5); // recalculate the sum, and spread the difference - due to approximations. // Since diff should be in the order of "some" samples, a division (resulting in zero) // is not sufficient, so we add the additional remaining samples in each tone/silence block, // at least until available. int diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence; if (diff>dtmfNTones) { // in this case, both these values would change, so it makes sense to recalculate diff // otherwise just keep the value we already have // should always be the case that dtmfNTones>1, as if 0, we don't even start processing, // and with 1 there is no difference to spread (no silence slot)... wxASSERT(dtmfNTones > 1); numSamplesTone += (diff/(dtmfNTones)); numSamplesSilence += (diff/(dtmfNTones-1)); diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence; } // this var will be used as extra samples distributor int extra=0; longSampleCount i = 0; longSampleCount j = 0; int n=0; // pointer to string in dtmfString sampleCount block; bool isTone = true; float *data = new float[tmp->GetMaxBlockSize()]; // for the whole dtmf sequence, we will be generating either tone or silence // according to a bool value, and this might be done in small chunks of size // 'block', as a single tone might sometimes be larger than the block // tone and silence generally have different duration, thus two generation blocks // // Note: to overcome a 'clicking' noise introduced by the abrupt transition from/to // silence, I added a fade in/out of 1/250th of a second (4ms). This can still be // tweaked but gives excellent results at 44.1kHz: I haven't tried other freqs. // A problem might be if the tone duration is very short (<10ms)... (?) // // One more problem is to deal with the approximations done when calculating the duration // of both tone and silence: in some cases the final sum might not be same as the initial // duration. So, to overcome this, we had a redistribution block up, and now we will spread // the remaining samples in every bin in order to achieve the full duration: test case was // to generate an 11 tone DTMF sequence, in 4 seconds, and with DutyCycle=75%: after generation // you ended up with 3.999s or in other units: 3 seconds and 44097 samples. // while(i < numSamplesSequence) { if (isTone) // generate tone { // the statement takes care of extracting one sample from the diff bin and // adding it into the tone block until depletion extra=(diff-- > 0?1:0); for(j=0; j < numSamplesTone+extra; j+=block) { block = tmp->GetBestBlockSize(j); if (block > (numSamplesTone+extra - j)) block = numSamplesTone+extra - j; // generate the tone and append MakeDtmfTone(data, block, track->GetRate(), dtmfString[n], j, numSamplesTone); tmp->Append((samplePtr)data, floatSample, block); } i += numSamplesTone; n++; if(n>=dtmfNTones)break; } else // generate silence { // the statement takes care of extracting one sample from the diff bin and // adding it into the silence block until depletion extra=(diff-- > 0?1:0); for(j=0; j < numSamplesSilence+extra; j+=block) { block = tmp->GetBestBlockSize(j); if (block > (numSamplesSilence+extra - j)) block = numSamplesSilence+extra - j; // generate silence and append memset(data, 0, sizeof(float)*block); tmp->Append((samplePtr)data, floatSample, block); } i += numSamplesSilence; } // flip flag isTone=!isTone; } // finished the whole dtmf sequence delete[] data; tmp->Flush(); track->Clear(mT0, mT1); track->Paste(mT0, tmp); delete tmp; //Iterate to the next track track = (WaveTrack *)iter.Next(); } /* save last used values save duration unless value was got from selection, so we save only when user explicitely setup a value */ if (mT1 == mT0) gPrefs->Write(wxT("/CsPresets/DtmfGen_SequenceDuration"), dtmfDuration); gPrefs->Write(wxT("/CsPresets/DtmfGen_String"), dtmfString); gPrefs->Write(wxT("/CsPresets/DtmfGen_DutyCycle"), dtmfDutyCycle); // Update selection: this is not accurate if my calculations are wrong. // To validate, once the effect is done, unselect, and select all, then // see what the selection length is being reported (in sec,ms,samples) mT1 = mT0 + dtmfDuration; return true; }
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); } } }