On May 1, 2013 03:18:50 PM Florian Jung wrote:
> Am 01.05.2013 08:34, schrieb Tim E. Real:
> > On May 1, 2013 01:33:25 AM Florian Jung wrote:
> >> Hi
> >> 
> >> I need a way to find out a tick-to-frame mapping, even if we're synced
> >> to an external device, thus not using our built-in tempomap.
> >> 
> >> I already know at which frame we are currently and how many frames i
> >> need to retrieve.
> >> I need to know at which tick we are currently (easy), and how many
> >> (sub)ticks will pass during these retrieved frames. Looking further into
> >> future would be even better (it would be great to know the (sub)tick
> >> position we'll be at after 1000-10000 audio frames.)
> >> 
> >> How can I get such one?
> >> 
> >> I need this already in AudioPrefetch::prefetch. Is there guesswork
> >> involved, because i don't know the tempo yet (in case of external sync)?
> > 
> > Ew, that's a really tough one.
> > 
> > You see, originally someone had written the syncing code (you can see it)
> > 
> >  to try and dynamically update the tempo map as it went along.
> > 
> > I found this was not practical as it involved lengthy filtering delays so
> > 
> >  the tempo map could not really be in immediate 'sync' with the
> >  incoming midi clock ticks. I could not find a way around it at the time.
> > 
> > So you will see that what I did was remove all that and simply drive
> > 
> >  the tick position *directly* from the incoming midi clocks.
> > 
> > It resulted in *rock* solid performance *guaranteed* not to drift no
> > matter
> > 
> >  how wildly the incoming midi clock (clock basically means external tempo
> >  )
> >  may swing or vary.
> > 
> > Unfortunately it means during external sync the tempo map is *not* used
> > 
> >  at all and is *not* to be used at all. That was the price paid.
> > 
> > It is *very* difficult to smooth out the incoming clock pulses and filter
> > them> 
> >  and derive a fairly 'stable' tempo from them - without delay - unless
> >  thousands of tempo fluctuations per second are acceptable.
> > 
> > Take a look at my tempo *recording* clock filtering options in the Sync
> > Dialog> 
> >  to see what I mean. I offer several options to the user depending on
> >  their needs, including no filtering at all for the utmost *accuracy*
> >  upon playback of the recorded tempo stream.
> > 
> > Ironically I do realize that this very same code *could* be used for
> > 
> >  dynamically updating the tempo map as it rolls along - which was
> >  the original plan way back.
> > 
> > Still, even with no filtering I think there would be an inherent delay in
> > the> 
> >  dynamic tempo being 'valid', and there *still* would be slight
> >  accuracy/drift problems as it rolls along.
> > 
> > That's why my direct-drive-ticks method is still the ultimate method, I
> > think.
> > 
> > But if we can find a way to additionally dynamically update the tempo map
> > too> 
> >  as it rolls along, so that stretchers/resamplers can use it, that would
> >  be
> >  good.
> 
> i don't really want to update the tempo map in the way you say. That
> would introduce evil locking problems, and still not help me.
> 
> Buuuut:
> > my tempo recording clock filtering code
> 
> couldn't we during every playback record the tempo into a *temporary*
> tempomap, which is then freed of any lag (offline, that is), and
> afterwards the real tempomap is replaces by this recording?
> 
> So there's no live-recording, but in the n-th playback, we always have
> the (n-1)-th tempomap, which should be the same, right?

Oh OK, that is exactly what I do for the tempo recording.

In the sync code (see below) I add each incoming tempo to a temporary list,
 first via a special dedicated TempoFIFO ring buffer (to decouple the threads):

song->addExternalTempo(...)

The TempoFIFO ring buffer needs periodic processing, so at the relatively slow 
 heartbeat rate I transfer these FIFO items into the temporary tempo_rec_list 
 here:

Song::beat()
{
  ...
      // Process external tempo changes:
      while(!_tempoFifo.isEmpty())
        MusEGlobal::tempo_rec_list.addTempo(_tempoFifo.get()); 
  ...
}

When recording is finished, *then* I transfer these recorded tempos to the real
 tempo map. (But *first* I ask the user in a popup dialog whether this is 
 what they really want, because there may be thousands of tempo changes.)
Do take a look here for the full story, here's a snippet:

Song::processMasterRec()
{
  ...
    if(QMessageBox::question(MusEGlobal::muse, 
                          tr("MusE: Tempo list"), 
                          tr("External tempo changes were recorded.\nTransfer   
                                                them to master tempo list?"),
  ...
    for(int i = 0; i < tempo_rec_list_sz; ++i)
      MusEGlobal::tempomap.addTempo(MusEGlobal::tempo_rec_list[i].tick, 
                                    MusEGlobal::tempo_rec_list[i].tempo, 
 ...

}

> Can you please me tell me the class, function or even source code line,
> where incoming tick synth is handled?

The exact place where incoming midi clocks are handled is here:

sync.cpp : MidiSeq::realtimeSystemInput()
{
  ...
  case ME_CLOCK:
  ...
    song->addExternalTempo(...).
  ...
}

That's where all my filtering takes place.
You can also see the older commented code I mentioned yesterday.

I forgot to point out that the older original code simply did not work,
 which is another reason I removed it and went with my simpler
 direct-drive method.
The old code was highly experimental and quite terrible.
One example of the problems it caused was that it could produce
 *negative* tempo, causing the playhead to move *backwards* and
 midi to play backwards while the audio (always) marches forward !!!

----

So, with a few changes you can probably leverage all this code
 to produce the off-line tempo map you want.

It almost does exactly what you need as is, I reckon.
Ask if you have any more questions about how it works.

Tim.

------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
Lmuse-developer mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/lmuse-developer

Reply via email to