Jump to content

BPM Berechnung im PIC


acidcode
 Share

Recommended Posts

Hi Thorsten,

hi *,

wie habt ihr bzw. Du das im Midibox Sequenzer eigentlich mit der BPM Berechnung gelöst.

Bei meiner ML-303 ist es ein simpler Lookup-Table über den ich einen Timer-Intervall setze und dann mit 24 PPQN jeweils einen IRQ auslöse.

Vorteil ist das es "schnell" und einfach ist  ;D.

Ein kleiner Nachteil dieser Methode ist, dass man bei den BPM keine Nachkommastellen einstellen kann  :-/

Das eher größere Problem dabei ist das ich dabei auf 24 PPQN "festgenagelt" bin, oder sollte ich 96 PPQN IRQs auslösen und dann nochmal während des IRQs bei Bedarf dividieren (zählen) ? Und vor allem: wie kriegt man da einen Shuffle rein (viele der User wünschen sich das halt)  ???

Ich wette es gibt ne Intelligentere Lösung, also bitte bitte gebt mir Tipps  ;D

Gruß,

Matze

Link to comment
Share on other sites

Servus Matze,

die MIDIbox SEQ arbeitet ebenfalls mit einer Lookup Table, weil sie weniger Speicher verbraucht als der Code, der zur Berechnung des Timer Reload Values notwendig waere. Bei einer hoeheren Aufloesung macht es natuerlich Sinn, die Tabelle durch eine Berechnungsroutine zu ersetzen. Die muss noch nicht einmal mit Floating Point arbeiten, 32bit Integer sollte ausreichen. Und die Division ist auch kein grosses Problem, es muss ja lediglich durch 60 geteilt werden, und nicht durch einen variablen Wert...

Die Berechnung des Reload Values fuer vierfache ppqn ist dann auch kein grosses Problem mehr, dazu wird das Ergebnis zweimal nach Rechts geshiftet (oder man teilt am Anfang nicht durch 60, sondern durch 15...)

Shuffle: hierbei muss man sich ganz grundsaetzliche Gedanken ueber die Software Architektur machen. Wenn der Sequenzer auch als MIDI Clock Slave arbeiten soll (was eigentlich der Normalfall ist), so ist es meiner Meinung nach am geschicktesten, entweder die intern generierte Timerfrequenz hochzuschrauben (MIDI Clock Master) oder die eingehenden Clocks mit Hilfe eines Referenztakts zu vervielfachen (MIDI Clock Slave), und diese "Microticks" dann zum Triggern des Sequenzer Handlers herzunehmen.

Shuffle selbst ist dann ganz einfach zu realisieren: bei geraden Steps werden ein paar Microticks hinzugezaehlt, und bei ungeraden werden sie wieder abgezogen - wichtig ist nur, dass die Anzahl der Ticks ueber den gesamten Track ausbalanciert ist, so dass bspw. bei einer vierfachen Aufloesung und 16 Steps der erste Step immer nach exakt 384 Microticks gespielt wird.

Da die Taktgenerierung ein wenig tricky ist, habe ich sie sogar dokumentiert, damit ich auch nach einem Jahr noch weiss, was ich damals angerichtet habe ;-)

; Some notes to the way how MIDIboxSEQ generates the internal 96ppqn clock
;
; MASTER MODE
; ~~~~~~~~~~~
;
; The period of USER_Timer will be configured based on bpm_table.inc which
; is a generated file (utils\gen_bpm_table.pl). The values are calculated 
; based on the formula: delay = (60 / (bpm * 24)) / prescaler_delay
; 
; For a common MIDI clock (24ppqn), 8 should be used as prescaler delay to 
; realize BPM rates from 48 to 255
; But MBSEQ works with 4 times resolution (96ppqn), therefore a prescaler
; delay of 2 is used here
;
; The USER_Timer hook increments the SEQ_CLK_REQ_CTR with every invokation
; which triggers the SEQ_CORE_Clk function. Using a counter instead of a
; request flag ensures that a clock event never get lost, even though the
; sequencer handler won't be called for a certain time - e.g. during a
; EEPROM write transfer
;
;
; SLAVE MODE
; ~~~~~~~~~~
;
; Could be realized by incrementing the SEQ_CLK_REQ_CTR by 4 with every
; received MIDI clock. But for the current implementation I spent some
; effort to realize 3 interpolated clock events between the received
; MIDI clocks in order to increase the resolution.
;
; This mechanism works that way: USER_Timer is used as reference
; counter which will be invoked every 500 uS. It measures the delay
; between two F8 events by incrementing a counter SEQ_INCOMING_CLK_CTR
; which will be registered in SEQ_INCOMING_CLK_DELAY on the next F8
; event.
;
; The delay value will be divided by 4, this is the preload value of
; SEQ_SENT_CLK_DELAY which defines the delay between interpolated clock
; events. The SEQ_SENT_CLK_DELAY will be decremented by USER_Timer
; every 500 uS. Once it reaches zero, a clock event will be triggered,
; and SEQ_SENT_CLK_DELAY will be reloaded by SEQ_INCOMING_CLK_DELAY / 4
;
; The SEQ_SENT_CLK_CTR ensures that never more than 3 internal clock
; events will be triggered by USER_Timer. This is to avoid timing 
; failures on BPM sweeps or jittering MIDI interfaces.
;
; And now the trick for stable timings: SEQ_MIDI_NotifyRx_Clk 
; (which receives the F8 events) increments SEQ_SENT_CLK_CTR by
; 4 - SEQ_SENT_CLK_CTR. 
;
; This ensures that the sequencer will always run in sync with
; the external MIDI clock, and that a 96ppqn clock event never
; get lost, regardless of jitter or BPM sweeps
;
; Copyright (C) 22th January 2004 by Thorsten Klose

Gruss,

       Thorsten.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...