Loop Play from within selection. (SHIFT+B)

When repeating a section (Edit > Repeat) the exact positions of the start and end points are often critical.
For very short selections it is easy to test the “loop position” with “Loop Play” (SHIFT + Play).
However, for a longer selection (for example repeating a 1 minute chorus) this is unduly time consuming (and if you’ve ever needed to do this you will know just how irritating it is).

The “B” key allows playback within a selection, but it stops at the end of the selection. What would be really useful would be to be able to play from an arbitrary point within a selection, and for playback to loop back to the beginning.

I realise that there are workarounds, but it would be so much more friendly and convenient to have this as a feature.

And I was about to suggest SHIFT + B for something there seems to be no easy workaround for :slight_smile: - if the mouse cursor was before the midpoint in the selection, SHIFT + B would play from there to the end of selection; if the mouse cursor was after the midpoint, SHIFT + B plays from start of selection to mouse cursor. Very useful for short selections. Aren’t the workarounds for your problem fairly easy - use B from hovering close to the end of the selection, then Space?

With your idea, does playback stop after traversing the entire selection from the beginning, or loop play from the beginning to where your mouse cursor was, or something else?



Gale

When looping, the most critical point is when the end of one time through becomes the beginning of the next time through.

“Counting the beats” and lining up the selection so that start and beginning are immediately before the onset of a beat are useful techniques to improve accuracy, but for music that either has complex rhythms or does not have a strong beat, there is no substitute for listening. The section that needs close attention is the transition as the repeat goes back to the beginning. The aim in selecting the best loop point is to create a seamless transition as the selection repeats. “B” then SPACE will not do because it does not play through the transition.

The only methods currently available are:

  1. Loop play the entire selection.
  2. Use the “Repeat” effect, then move the cursor to play through the transition, then if it is not exactly correct, Undo, then adjust the selection and try again. (this is the workaround).

The reason that the workaround is so awkward is that you can’t see exactly where the transition is, so making the necessary adjustments to the selection become very much more tricky.

This feature request is for a means (and I’m not really fussy about what the means is - SHIFT+B just seems like an obvious method) to play the last part of a selection and for it to immediately (without stopping or pausing) continue playback from the beginning of the section. The feature is identical to Loop Play but with playback beginning at a point other than the start of the selection.

Let me see if I understand you, let us imagine we have 60 seconds of audio, we (somehow–use a region label?) mark a region – let us say from 00:10 to 00:30; we set the cursor at 00:20 and issue our command. What we want to see happen is that the audio starts playing at 00:20 and plays through until 00:30 and then (with no perceptible pause) jumps back to 00:10 and continues playing (and I am assuming it’s going to stop at 00:20). Is this right?

Yes.

I don’t mind if it then stops at 00:20 or continues to loop.
Putting together the ideas of “Play to/from the current pointer position to/from the start/end of the selection” (“B” key) and “Loop Play” (SHIFT+Space) it would be logical to continue looping until manually stopped, but for the purpose that I describe it does not matter if it continues to loop or stops when it gets back to 00:20.

A more realistic example might be that I have a 6 minute piece of music that I want to extend to around 8 minutes (for example to fit an 8 minute slide show or video).
So I decide to loop the section from about 1:23 to 3:30 (I’ve recognised that this is starts at the beginning of a musical “phrase” and ends at the end of a musical phrase). However, I need to get the loop positions exact so that it will play smoothly without jumping after I have “looped” it (Repeat effect). I don’t want to have to wait for 2 minutes and 7 seconds to find out that the loop length is a little bit too long/short.

I could upload an actual example if it would help - I do a lot of this kind of thing.

Let me look at the code and see how “play” works. I do not imagine that it would be too hard to create a proof-of-concept as long as we did not want to add a lot of interface (like adding to the prefs etc.). I will work against SVN HEAD so that you may apply a patch to try it out (assuming I can pull it off). You do realize that there is slim-to-no chance of this getting committed pre-2.0, right? Anyway, here is the design specification I will use:

add menu item “Continuous Loop Play” to Transport menu, keyboard shortcut SHIFT+B
(it could go anywhere and be called anything but the only way I know how do “drive” the event is via a menu item)
pseudo-code:
OnContinuousLoopPlay {
is current cursor location (CCL) in a labeled region (LR)
if no – bail out with minimal wxMessageBox warning
if yes –
play from CCL to end of LR
skip back to beginning of LR and continue playing until “Stop” (via tool, menu keypress)
}
For production we could add a stored pref item for “one time” (the way I would most likely use it–I have that feature on a production deck in the studio) or “continuous loop” (the way you seem to want to use it).

I will try to look at this tonight.

I guess it’ll depend a lot on what you find when you look at the code, but personally I’d be OK with “loop play” added to the “B” key behaviour.
What I mean by that is that the “B” key plays form the current pointer position and “Loop Play” loops back to the start of the selection on reaching the end of the selection.
Put those together and you have “Loop Play from current pointer position”.

Merry Oktoberfest!

Patch against this afternoon’s SVN HEAD (30Oct2010) which seems to perform as specified. I did NOT do exhaustive testing for conditions like:
no (wave|label)track
multiple (wave|label)tracks
non-44100 project rates
mono tracks
long tracks
overlapping label regions (now that I think about it this might cause problems)

Have fun! If you have questions, problems or comments let me know.
LoopFromCursor.patch (9.79 KB)

Merry Oktoberfest to you too Edgar.

Unfortunately I’m getting some really strange results, but before that I’m just wondering why you decided to use labels as the loop region rather than the current selection. Is there a technical reason for that? If not, then I think it would be easier from a user perspective to loop the selection rather than using a label region.

Also I notice that key presses when a label track is selected create a new label (I don’t often use labels so I’d not noticed this behaviour). This makes it a bit awkward to use labels to define the loop region as any adjustments that are made to the label will leave focus on the label track.

So for the strange results:

  1. Place the playback cursor on an audio track within a region defined by a region label. (Example: Label region from 10.0 to 30.0 and cursor at 25.0)
  2. Press SHIFT + B

Playback commences from the playback position (25.0)
On reaching the end of the label region, the cursor jumps to the start of the label region (jumps from 30.0 to 10.0 as expected)
The audio that is played is a repeat of what has just been played - it is not playing the correct audio. Rather than playing from 10.0 it repeats the audio 25.0 to 30.0.

If the cursor is placed outside of the label region (assuming only one label region in a one audio track project), the on SHIFT + B Audacity freezes.

I did warn you that this code was not thoroughly tested! During the production process I used 30 seconds of generated noise and relied on visual inspection to determine appropriate action. I only tested it with one actual MP3 file and that was modern jazz with no vocals and almost no structure (I have no idea why I use that file – it was a mistake, a song I had never heard before).

As for why I chose to use Labeled Regions, as far as I can tell it is impossible to make a selection and then click somewhere within it to set the cursor – the selection goes away. I am a neophyte when it comes to using Audacity there may well be a method for setting off a region of audio other than Labeled Regions but since I have just spent many days working with the Label code it was simply familiar territory.

If you take a quick look at the patch, you will see the area in AudioIO.cpp where the loop back code is. You will see that the variable names are meaningless: mTime, mT0 etc. I suspect that I need to reset another variable to the beginning of the Labeled Region so that it starts playing the music there. I will try to give that a look see!

That’s correct, though with two exceptions:
“Edit menu > Region Save/Region Restore”
and “Edit menu > Region Lock”.

However, “Play to/from the current pointer position to/from the start/end of the selection” with the “B” key does not use either of these features. It plays from the “pointer” position (without clicking on the track). See “Play to selection” here: http://manual.audacityteam.org/index.php?title=Playing_and_Recording

I did experiment with that but it required a deeper understanding of the way the mouse pointer location was used and would’ve taken quite a bit more time for me to comprehend. The current behavior, while not elegant, was simple to implement based on code that I already had and given that this is just proof-of-concept and unlikely to ever be committed I chose to go the more simple route. The major problem is that I have not figured out how to initiate a non-menu related keypress generated activity; I know that it is possible as there are quite a few of them, so far it has always been easier for me to just add an extra menu item (remember, I do not use a mouse nor a keyboard – I control Audacity vocally so I never see the menus, I always access them via shortcut key – usually in some macro triggered vocally).

I have spent the day on this and have been down two more dead ends! I was hoping to trick the looping mode into starting from deep within its buffer but cannot see any way to do so. Now the only way I can see to do this is to create two actions, the first being “play region once” starting from the cursor and going to the end of the selection then immediately going into the loop mode. This requires starting from scratch again and I need some outdoor time as today is the last (and almost only) nice day of summer! Oops, spoke too soon–it’s getting cloudy and cold now!

Edgar:
This thread on nabble http://audacity.238276.n2.nabble.com/WaveClip-mis-reporting-start-time-td5552788.html#a5552788 might help. From what I can glean from it, using the “C” command to do a cut preview creates a temporary track. Perhaps that would work with what you’re trying to do?

– Bill

Bill–thanks, I have been following that thread and I suspect doing a temporary track might be the elegant solution. Copy audio from cursor to end-of-selection into track then copy audio from start-of-selection to cursor into track. Now we have a temporary track that looks like B-A and the original like A-B and we can loop play the temporary track.

However, after taking a break to weed my fuchsias I came back and discovered that I could do the job using the “play B” then “loop play A+B” method so I now have it working as advertised (but you can still crash Audacity by intentionally misusing the function so I need to debug the fringes and improve the error checking). The main code looks like:

void AudacityProject::OnPlayLoopedFromCursor()
{
   if( !MakeReadyToPlay() )
      return;

   AudacityProject * activeProject = GetActiveProject();
   double currentCursorLocation;
   bool viable = activeProject->ViableStartAtCursor(&currentCursorLocation);
   if (viable) {
      GetControlToolBar()->PlayPlayRegion(currentCursorLocation, activeProject->mLoopingRegionEnd);
      int streamToken = activeProject->GetAudioIOToken();
      while (gAudioIO->IsStreamActive(streamToken)) {wxMilliSleep(50);}
      gAudioIO->StopStream();
      activeProject->SetSel0(activeProject->mLoopingRegionStart);
      activeProject->SetSel1(activeProject->mLoopingRegionEnd);
      if(!MakeReadyToPlay())
         return;
      else
         GetControlToolBar()->PlayPlayRegion(activeProject->mLoopingRegionStart, activeProject->mLoopingRegionEnd, true);
   }
}

I will post a patch sometime before I leave for work in the AM.

The crashing bug was a silly typo and testing all of the obvious extreme conditions proved to be fairly quick and as that section of the code has been heavily tested here on my system for a couple of months now I feel comfortable that it’s reasonably robust.

There is one fairly trivial “gotcha”; if you have two Label Regions which overlap and you click the cursor in a region of audio which is contained by both Labeled Regions, the algorithm always uses the first region it finds. Given that the original design goal was to start playing at cursor location until the end of the selection then jump back to the beginning of the selection and loop until stopped, that is the way this works now changing one “true” to “false” in the code causes it to play only one time – from cursor to end to start to cursor. If I had a use for it that is the way I would probably use it.

As always, comments, suggestions, criticisms and bug reports are welcome!
LoopFromCursor2.patch (5.52 KB)

I’m obviously a fool when it comes to looping. :slight_smile: Obviously I see the time saving, but what (approximate) time range is it you want to loop? If 10s to 30s, why is the end of the loop set to 20s? If 10s to 20s, why start playing outside the loop region instead of at say 15 seconds? I’ve seen a few requests (not on Wiki FR yet) to loop between mouse cursor and cursor (including the implied cursor at the start of the selection); and even I see one to use B in some way to loop play from mouse cursor to end of region, carrying straight through to start of region thence to end of region… but to stop at (or loop back from) the mouse cursor seems odd. :confused:

On a different tack, does anyone here like the practice of loop playing the whole track when there is no selection, irrespective of the position of the cursor? There are a fair number of votes (again some not yet added) to take the cursor into account (either loop from cursor to track end, or from cursor to cursor, playing through from the track end via the start to the cursor).



Gale

As I mentioned, I do not use looping with Audacity (I do use it a lot in an aid to memorizing but do so on my pro deck where looping works just exactly the way I need it to but with an incredibly clunky interface). The patch I supplied is specific to stevethefiddle’s need and is probably of little interest to most users without a very good use case and detailed instructions. I really did not understand OP’s use case but coded to spec.

As for loop behavior with no selection, I find it wrong–no selection implies no availability to loop IMHO. I think looping should be disabled when there is no selection (or–worst case, that a selection is forced between mouse and cursor before looping).

Here’s a nice easy example to illustrate:

The task is to extend the track by about 2 minutes.
Select from about 25 seconds to about 1 minute 15 seconds.
Press SHIFT+Spacebar.
If the “loop points” are in exactly the right place then it will loop seamlessly.

Adjust the selection until the loop plays seamlessly then use “Effect > Repeat” with the number of repeats set to 2.
The original track was 2:36.6
The new (extended) track is 4:16.3. Mission accomplished.

Here is the “join” - from 1:00 to 1:20 of the extended version with the loop positions in the right place.:

For this particular example there is a simple workaround but in many other cases there is not substitute for listening to the loop.

It would be far more useful if loop playback could be from the cursor or pointer position.
This would not necessarily have to be the default behaviour when pressing SHIFT+Spacebar, it could be the same keyboard combination as for looping a selection from the pointer position (which I’m suggesting would be a good use of SHIFT+B).