Let sample tracks play from any song position #3133

Merged
merged 15 commits into from Jan 5, 2017

Projects

None yet

6 participants

@BaraMGB
Contributor
BaraMGB commented Nov 26, 2016

Okay, let's test this. I hope I found a solution that works for all.

@Umcaruje
Member
Umcaruje commented Nov 26, 2016 edited

So I did some testing:
screenshot from 2016-11-26 12 45 53

It works really nice when I jump the playhead around and there's low CPU usage

Bugs:

  • When resizing the windows the CPU usage goes really high
  • CPU usage also goes high when you have a lot of sample tracks and you zoom in or out
  • When scrolling and resizing windows there are very noticeable clicks in the audio
  • The sync breaks when the playhead mode is set to anything other than to go back to the beginning after stopping (screenshot from 2016-11-26 12 49 15 screenshot from 2016-11-26 12 49 06)
  • It seems that when you actually resize the sample track so it's bigger than it's normal size, the part with no sample plays random parts of previous samples, or even stuff I previewed beforehand. I'll try to make a video later today.
@Umcaruje
Member

Here's a video of the weird behaviour: https://youtu.be/Hh9at-DF7hI

@BaraMGB
Contributor
BaraMGB commented Nov 29, 2016

Click noises on resize and scrolling Song Editor should be fixed now.

@softrabbit
Member

How well does this cope with time signature and/or tempo automation?

@BaraMGB
Contributor
BaraMGB commented Nov 29, 2016

How well does this cope with time signature and/or tempo automation?

Sorry, thats not implemented yet. Please let's do the things step by step.

@BaraMGB
Contributor
BaraMGB commented Dec 11, 2016

@Umcaruje the fourth point should be fixed now. You can now looping, change songposition per mouse and per left/right key. mute and unmute the track, solo and unsolo an other track, stop pause playing and all that stuff. It will be synced perfectly ( I hope 😄 )

@zonkmachine
Member

Bloody amazing!

@BaraMGB BaraMGB added the in progress label Dec 12, 2016
@tresf
Member
tresf commented Dec 15, 2016

@BaraMGB I'm still getting some pretty bad artifacts if the sample is extended past its length... (white noise, clicks)

untitled

@BaraMGB
Contributor
BaraMGB commented Dec 15, 2016

My plan is to limit the TCO length to sample length. I think this is the simplest way to avoid this.

@BaraMGB
Contributor
BaraMGB commented Dec 15, 2016

@tresf okay, I guess I fixed it. Can you test this again?

@tresf
Member
tresf commented Dec 16, 2016

artifacts if the sample is extended past its length

[fixed] Can you test this again?

Confirmed, the artifacts are gone.

@Umcaruje
Member

Do any artifacts occur when you add an empty tco, without any sample loaded?

@tresf
Member
tresf commented Dec 16, 2016

Do any artifacts occur when you add an empty tco, without any sample loaded?

None.

screen shot 2016-12-16 at 12 46 30 pm

@Umcaruje
Member

Awesome 👍

@tresf
Member
tresf commented Dec 16, 2016

@Umcaruje @BaraMGB @softrabbit I think this is ready to merge. I understand time signature will break this however we have many bugs today with time signature and seeking ahead. I want this in 1.2.0-RC2 so that we get solid usage and feedback on it.

@Umcaruje
Member

The drawing sequence needs to be simplified so it won't produce such high cpu usage on redraws, though I guess that could be an issue for a seperate PR. I'm going to do some more thorough testing now.

@Umcaruje
Member

Ok so I found a problem: when you change the time signature to something other than 4/4 visually the sample view breaks. The track seems to sync up properly to the new time signature, but it's off from the drawn waveform. And on 3/4 time signature when you add a blank element it looks like this:
image
And it should be 1 measure long as usual

@BaraMGB
Contributor
BaraMGB commented Dec 17, 2016

Oh boy, that time signature stuff drives me crazy. I hope my thoughts about that and the resulting calculations are correct. Please test this out. @tresf @Umcaruje

@tresf
Member
tresf commented Dec 17, 2016

👍

screen shot 2016-12-17 at 11 22 41 am

@zonkmachine
Member

Works might well. Is it screaming hard to have this work in the Beat/Bassline Sample Track too?

src/tracks/SampleTrack.cpp
@@ -394,10 +454,12 @@ void SampleTCOView::paintEvent( QPaintEvent * pe )
/ (float) m_tco->length().getTact() :
pixelsPerTact();
+ float nom = Engine::getSong()->getTimeSigModel().getNumerator();
+ float den = Engine::getSong()->getTimeSigModel().getDenominator();
+ float ticksPerTact = DefaultTicksPerTact * ( nom / den );
@zapashcanon
zapashcanon Dec 17, 2016
float ticksPerTact = DefaultTicksPerTact * nom / den;
src/tracks/SampleTrack.cpp
+ {
+ if( sTco->isPlaying() == false )
+ {
+ f_cnt_t sampleStart = ( _start * framesPerTick ) - ( sTco->startPosition() * framesPerTick );
@zapashcanon
zapashcanon Dec 17, 2016
f_cnt_t sampleStart = framesPerTick * ( _start - sTco->startPosition() );
src/tracks/SampleTrack.cpp
+ if( sTco->isPlaying() == false )
+ {
+ f_cnt_t sampleStart = ( _start * framesPerTick ) - ( sTco->startPosition() * framesPerTick );
+ f_cnt_t tcoFrameLength = ( sTco->endPosition() * framesPerTick ) - ( sTco->startPosition() * framesPerTick );
@zapashcanon
zapashcanon Dec 17, 2016
f_cnt_t tcoFrameLength = framesPerTick * ( sTco->endPosition() - sTco->startPosition() );
@zonkmachine
Member
zonkmachine commented Dec 17, 2016 edited

clicktrack

clicktrack.zip Edit: re-uploaded with correct samples...

OK. I made a test project with two different length click tracks and they sync perfectly. However, every now and then the samples will cut out after the first click on one and sometimes both sides. I haven't seen this on export.

@BaraMGB
Contributor
BaraMGB commented Dec 17, 2016

However, every now and then the samples will cut out after the first click on one and sometimes both sides. I haven't seen this on export.

I guees what you notice is the sync after loop back? You mean the very first click when the position jumps back to the begin of the loop, right?

@zonkmachine
Member

I guees what you notice is the sync after loop back? You mean the very first click when the position jumps back to the begin of the loop, right?

No, it's not only after a loop but on the first run too. The first sample randomly cuts out in the example project.

@BaraMGB
Contributor
BaraMGB commented Dec 18, 2016

If I opened the project the samples weren't loaded. The TCOs were empty. So I drag they into the TCOs. Probably a bug. But I couldn't hear any cut outs. Sometimes a millisecond is missing after the loop jumps back to the beginning. Can you please provide me a video? @zonkmachine

@zonkmachine
Member

If I opened the project the samples weren't loaded. The TCOs were empty. So I drag they into the TCOs. Probably a bug

No. Probably me but samples aren't bundled with the project so I just threw them in there free style...

Can you please provide me a video?

I'll try and record something.

@zapashcanon

@BaraMGB, did you see my review ? The first line is not very important, but the two others will prevent a few useless operations.

@BaraMGB
Contributor
BaraMGB commented Dec 19, 2016

@zapashcanon sorry for not answering. Yes of course I see your review. Thank you very much for this. I will insert your suggestions as soon as possible. 👍

@Umcaruje
Member

@BaraMGB any progress on this? There seems to be a wish for this feature to ship with RC2, and I would really like to get it out before new year, if possible.

@BaraMGB
Contributor
BaraMGB commented Dec 29, 2016

@Umcaruje the bug that @zonkmachine found is a little bit hard. I made a break from lmms for refresh my mind 😄 but I don't have time before january. Sorry for that. Next week I'll get back to this.

@Umcaruje
Member

No problem, take your time. @tresf should we release RC2 without this? I think our users deserve a Christmas present 🎄

@BaraMGB
Contributor
BaraMGB commented Jan 1, 2017

Okay, to explain the bug: if the loop goes back to start the first tick is not played. It begins one tick to late.

@zonkmachine
Member

https://github.com/LMMS/lmms/blob/master/src/core/Song.cpp#L262:L274

I thought there was cases in the code where we go one tick ahead (when we're playing) but I can't find any examples of it.

@zonkmachine
Member

if the loop goes back to start the first tick is not played

Also, the glitchy tick on loop back, is that the first tick of the next bar before a loop? So the whole audio track is one tick off... but instrument tracks isn't?

src/tracks/SampleTrack.cpp
- f_cnt_t sampleStart = ( _start * framesPerTick ) - ( sTco->startPosition() * framesPerTick );
- f_cnt_t tcoFrameLength = ( sTco->endPosition() * framesPerTick ) - ( sTco->startPosition() * framesPerTick );
+ f_cnt_t sampleStart = framesPerTick * ( _start - sTco->startPosition() );
+ f_cnt_t tcoFrameLength = framesPerTick * ( sTco->endPosition() - sTco->startPosition() );
f_cnt_t sampleBufferLength = sTco->sampleBuffer()->frames();
//if the Tco smaller than the sample length we play only until Tco end
//else we play the sample to the end but nothing more
f_cnt_t samplePlayLength = tcoFrameLength > sampleBufferLength ? sampleBufferLength : tcoFrameLength;
//we only play within the sampleBuffer limits
if( sampleStart < sTco->sampleBuffer()->frames() )
@zapashcanon
zapashcanon Jan 1, 2017
if( sampleStart < sampleBufferLength )
@BaraMGB
BaraMGB Jan 2, 2017 Contributor

Thank you, sometimes I'm a little bit blind. ;)

@BaraMGB
Contributor
BaraMGB commented Jan 2, 2017 edited

@zonkmachine the next problem is, this seems to be a timing issue. On my big computer (i7) the loop seems perfect. So on different computers it appears different.

edit: there's something fishy, but I don't see it. 😩

@BaraMGB
Contributor
BaraMGB commented Jan 5, 2017

@zonkmachine : perhaps this is a stupid idea:
https://github.com/BaraMGB/lmms/blob/sampletrack/src/core/Song.cpp#L341-L344
Here the loopback position emits the signal one tick earlier. Your clicktrack seem okay now. But may be the sampletrack is cut off at the end now ( one tick ) I can't hear and test it. For me it sounds okay.

src/core/Song.cpp
+ if( m_playPos[m_playMode] == tl->loopEnd() - 1 )
+ {
+ emit updateSampleTracks();
+ }
if( m_playPos[m_playMode] >= tl->loopEnd() )
{
m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() );
m_elapsedMilliSeconds =
( ( tl->loopBegin().getTicks() ) * 60 * 1000 / 48 ) /
@zapashcanon
zapashcanon Jan 5, 2017 edited
m_elapsedMilliSeconds = tl->loopBegin().getTicks() * 1250 / getTempo();
@zapashcanon
zapashcanon Jan 5, 2017 edited

And the same thing on lines 269, 326, 409, 574 and 643.

@zonkmachine
zonkmachine Jan 5, 2017 Member

No. This will make it harder to deduce where 1250 came from in the first place. The compiler does operations on real numbers for us.

@BaraMGB
BaraMGB Jan 5, 2017 Contributor

I don't want to change code I don't have to touch. I want to have this PR as clean as possible. We can make an extra PR with code cleaning stuff.

src/core/Song.cpp
+ if( m_playPos[m_playMode] == tl->loopEnd() - 1 )
+ {
+ emit updateSampleTracks();
+ }
if( m_playPos[m_playMode] >= tl->loopEnd() )
@zapashcanon
zapashcanon Jan 5, 2017
else if( m_playPos[m_playMode] >= tl->loopEnd() )
@zapashcanon
zapashcanon Jan 5, 2017

I would also switch them, as the second one is likely to be true more often.

@BaraMGB
BaraMGB Jan 5, 2017 Contributor

This is a great idea. I've changed this.

@zonkmachine
zonkmachine Jan 5, 2017 edited Member

I think you should just try and move the whole loop one tick earlier. (in if( checkLoop ) )

if( m_playPos[m_playMode] >= tl->loopEnd() )
{
     m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() );

to something like (pseudocodeish...):

if( m_playPos[m_playMode] >= tl->loopEnd().getTicks() - 1 )
{
     m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() - 1 );
src/tracks/SampleTrack.cpp
@@ -298,7 +311,7 @@ void SampleTCOView::updateSample()
// sample-tco contains
ToolTip::add( this, ( m_tco->m_sampleBuffer->audioFile() != "" ) ?
m_tco->m_sampleBuffer->audioFile() :
- tr( "double-click to select sample" ) );
+ tr( "double-click to select sample" ) );
@Umcaruje
Umcaruje Jan 5, 2017 Member

2 spaces added on accident

@Umcaruje
Member
Umcaruje commented Jan 5, 2017

Ok so we went over this PR on Discord and both @BaraMGB and @zonkmachine agree on a merge. I'm going to merge this once Travis is done buidling, and we can make an RC2 🎉

There are a few quirks in the GUI drawing and also one minor bug when looping, and that can be adressed later.

@Umcaruje Umcaruje changed the title from lets Sampletrack play from any song position to Let sample tracks play from any song position Jan 5, 2017
@Umcaruje Umcaruje removed the in progress label Jan 5, 2017
@Umcaruje Umcaruje merged commit 43a77a0 into LMMS:master Jan 5, 2017

1 check was pending

continuous-integration/travis-ci/pr The Travis CI build is in progress
Details
@liushuyu liushuyu added a commit to tonychee7000/lmms that referenced this pull request Jan 10, 2017
@BaraMGB @liushuyu BaraMGB + liushuyu Let sample tracks play from any song position (#3133)
* play sampletracks from any song position

* take care of TCO length

* TCOs shouldn't be updated when SE window is resized

* take care of zooming level

* takes care on all song position changes and mute/solo tracks now

* playes the sample only within the buffer limits

* takes care of time signature changes

* some minor code improvements (zapashcanon)

* loopback one tick earlier

* minor code changes

* get rid off clicks by resize and scrolling song editor

* removes playhandle by remove TCO

* minor bugs on manipulating TCOs in Song Editor

* update on add sample by playing

* white spaces 1
7e98aed
@zonkmachine
Member

@zonkmachine : perhaps this is a stupid idea:
https://github.com/BaraMGB/lmms/blob/sampletrack/src/core/Song.cpp#L341-L344
Here the loopback position emits the signal one tick earlier. Your clicktrack seem okay now. But may be the sampletrack is cut off at the end now ( one tick ) I can't hear and test it. For me it sounds okay.

The glitches are still there but not as prominent. I'm looking into it.

@zonkmachine
Member

So on different computers it appears different.

Apparently libsndfile corrected some buffer overflow error in 1.0.26 and I'm on 1.0.25 so this could be related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment