Variation of the Ableton tempo in % (MIDI)
Hello everyone :)
I have been discovering M4L for a few days and my poor English absolutely does not help me advance in my search.
Until then, for a few years I worked my bass on Guitar Pro and Ableton which had the role of an instrument. Guitar Pro has a very useful asset for work, which is not found elsewhere, it is the management of the % tempo, per range of +/-5%.
To summarize: when reading the score, we select the tempo and the "-" & "+" keys on the keyboard allow you to increase or decrease the tempo in a range of 5%. There is also a drop-down menu with a certain number of % to choose from and there is also the solution to fill in the tempo we want this time in bpm.
The disadvantage is that all this is not controllable in MiDi...
The idea would therefore be to export the pieces, exercises etc... from GP to Ableton in MiDi and use M4L to build a work tool that would respond to this:
Show in the same pop-up:
A - the original tempo (I found that)
B - the value in % of the new tempo (100% if = at the original tempo)
C - the tempo obtained (A x B = C)
Assign a MiDi controller (in my case MC8, why not equipped with Lehle Dual Expression S) that can:
+5% of A
-5% of A
Return to the original tempo A
So I started writing a patch by inquiring here and there. I will propose it to you below in image format but also in writing, maybe the study, the correction this one can interest you!
At this stage, I am not getting the desired result, and for a total novice at the start of this project, it is not necessary to have already spent a few hours there! )
Appointment at the next message...
Thank you in advance!
Sincerely,
Jérôme
Written patch:
BLOCK 1:
I have not yet grasped the purpose of this BLOCK.
I start with an object [loadbang] that is linked to the left entry of a message (path live_set),
From the message (path live_set) I go to an object [live.path],
From the left output of the object [live.path] I go to an object [send path_to_live]
BLOCK 2:
Just like BLOCK 1 I did not grasp the purpose of this BLOCK...
I start with an object [loadbang] that is related to left input of a message (property tempo),
From the message (property tempo) I go to the left entrance of an object [live.observer],
From an object [receive path_to_live] I go to the right entrance of the same object [live.observer] seen in the previous point,
From the left exit of the object [live.observer] I then go to an object [send tempo_Live]
BLOCK 3:
Just like BLOCK 1 & 2, I didn't grasp the purpose of this BLOCK either...
From a [receive tempo_Live] I go to the left entrance of an object [float],
From this object [float] I enter an object [send tempo_modif]
BLOCK 4:
The purpose of this Block is to display the tempo displayed in Live.
From a [tempo_Live receive] I go to the left entrance of an object [float] but also to an object [deferlow]
From this object [deferlow] I enter an object [live.numbox] to whom I ask to display the current (original) BPM tempo of Live.
BLOCK 5:
This block 4 begins with 2 approximately the same paths. For everyone:
An object [textbutton] with one displaying "-5%" and the other displaying "+5%". You will have guessed it, these two buttons have the role of increasing or decreasing the original tempo by 5%. Each of these objects is directed towards an object [t b b],
The left exit of each object [t b b] goes towards the left entrance of an object [float],
For each path an object [receive tempo_Live] goes again to the left input of these same objects [float],
Each object [float] heading towards an object [expr ...] a formula specific to each path to calculate
The 5% decrease: [expr ($f1 * 0.95)]
The 5% increase: [expr ($f1 * 1.05)]
Each of these formulas then joins towards the left entrance of a single object [clip inspector] calibrated as follows: [clip 20. 900.],
The output of the object [clip 20. 900.] goes to 3 objects:
An object [t f b] whose left output goes to the left input of a message (set tempo $1) and the right output goes to an object [live.numbox] supposed to show me the modified tempo in BPM
An object [t b b] whose left exit joins BLOCK 7,
A 2nd object [send tempo_modif] (there I have a doubt......),
The previous message (set tempo $1) goes to an object [loadbang],
This object [loadbang] goes to an object [deferlow],
This object [deferlow] goes to the left entry of a message (property tempo),
This message (property tempo) goes to the left input of an object [live object],
The right entry of this same object [live.object] receives an object [receive path_to_live]
BLOCK 6:
This block starts in the same way as BLOCK 5 except that it has only one path. The purpose is to RESET the variation and return to the original tempo.
An object [textbutton] displaying "RESET" goes to an object [t b b],
The left output of this object [t b b] goes to the left entry of an object [float],
An object [receive tempo_Live] goes to the left entrance of this same object [float] seen previously,
This object [float] goes to the left entry of a message (set tempo $1),
This message (set tempo $1) goes to an object [loadbang],
This object [loadbang] goes to an object [deferlow],
This object [deferlow] goes to the left entry of a message (property tempo),
This message (property tempo) then goes to the left input of an object [live.object],
The right entry of this same object [live.object] receives an object [receive path_to_live]
BLOCK 7:
This BLOCK, which begins with 2 paths, aims to display the variation in % of the tempo.
One [Loadbang] object per path goes to the left input of a [float] object for each path as well,
The left entry of these [float] objects also receives a different object for each:
An object [receive tempo_modif] for one,
An object [receives tempo_Live] for the other,
Finally the left input of the [float] object that receives the [receive tempo_Live] object also receives an [delay 20] object that itself receives the output of the [Loadbang] object from the other path. Reread well here.
It is then that the two objects [float] meet on an object [expr... ] allowing the calculation of the desired result: [expr (($f1 / $f2) - 1) * 100.],
This formula [expr (($f1 / $f2) - 1) * 100.] then goes to an object [live.numbox] supposed to display the % of tempo variation in %
RESULTS:
Upon opening Live and inserting the patch on a MIDI track, it displays:
An original tempo of 120 BPM for an original tempo of 120 BPM in Live,
A modified tempo of 20 BPM,
A % of tempo variation of 255%,
When I click on the +5% or -5% buttons:
The % of variation goes to 0,
The modified tempo remains at 20,
The tempo in Ableton goes to 20 but the display of the original tempo in Max remains at 120 BPM
You will find in the following message the image of all this

Thank you in advance for your help!
Small clarification if I have not done it before (even so, it is better 2 times than one!), I do not have Max in standalone but only Max from Ableton Live 12 Suite.
Most of what I wrote is the result of a long work with among other things ChatGPT, various readings, I absolutely do not master everything. But nevertheless very curious to learn, it is my English that is a big brake for me.
Sincerely,
Djé
ChatGPT is notoriously bad at describing/generating Max patchers, and your screenshot is a good example of that. There is a lot of non-sense going on, which would be a pain to debug as beginner. I strongly advice you to get familiar with Max basics and most usual objects (for example by following these tutorials or a lot of other ones you can find on Youtube) before attempting to do anything with AI, which is by the way a general use about using LLM: make sure you are able to understand and verify the information by yourself.
Although some points are not very clear to me (are we supposed to change Live tempo or GP tempo? Are the ±5% changes relative to the initial tempo value or the current value?), here is a more meaningful patch doing what I guess the patch you posted above is supposed to do.
To understand it, study common objects like [trigger], [route], [prepend], and basic concepts especially what hot and cold inlets are, and order of operations covered in basics tutorial 5.
Also learn how to share you patches using Copy compressed.
And if by any chance you speak french I can also help in french :)
Bonjour TFL,
Merci beaucoup pour ta réponse qui, avant tout me rassure du fait que le sujet ait pu attirer une attention et être lu ! ...et puis le français m'apporte un certain confort !
Merci également pour les tutos Cycling '74, Youtube ainsi que le patch.
Après l'étude du patch que tu m'as proposé via de nombreuse lectures (et traductions !) des "Help" et "Reference", j'ai pu retravailler celui-ci afin d'obtenir le résultat que je voulais et j'en suis assez satisfait !
Il reste quelques détails que j'aimerais affiner comme, dans le désordre :
Lorsque le Tempo modifié est différent du tempo initial, si par malheur il ya un click sur INIT, le Tempo modifié (ou Tempo Live dans ce cas) devient le Tempo Initial,
Lors d'un changement de tempo sur Live (changement de projet, changement de tempo manuellement sur un même projet (...) l'action sur le bouton INIT ne suffit pas. Il est nécessaire d' ajouter une action RESET pour rendre le Patch à nouveau utilisable :
=> Exemple :
En admettant le patch avec un Tempo initial à 135.00 bpm :
Tempo Live et Tempo modifié à 155,25 bpm,
La Variation à 115%,
Nous désirons désormais revenir à un Tempo initial de 120.00 bpm :
Double clic sur le tempo dans Live :
Dans Live le tempo affiche 120.00 bpm, ainsi que le Tempo Live dans le patch, le tempo de Live a donc bien été lu,
Le Tempo initial quant à lui affiche toujours 135.00 bpm,
Le Tempo modifié affiche lui aussi toujours 155.25 bpm
Enfin la Variation affiche 88.89%, elle a pris en compte la modification du Tempo Live (intéressant)
Une action sur INIT nous donne :
Les Tempo Initial, Tempo Live et Tempo modifié à 120.00 bpm,
La Variation est revenue à 100%
Cette situation me convenant, je désire alors faire varier de +5% ce tempo de 120.00 bpm :
Un clic sur +5% nous donne :
Tempo initial à 120.00 bpm, ça n'a pas bougé,
Les Tempo Live (et le tempo dans Live) et Tempo modifiés affichent 126,75 bpm (?!!)
La Variation affiche 105.62% (?!!!)
=> INIT n'a pas suffit. Pour qu'une initialisation soit complète, au paragraphe 2, après l'action INIT, je dois rajouter une action RESET.
Comment me passer de cette action RESET sans perdre la fonction première de ce RESET ? (voir ci-dessous pour les définitions de INIT et RESET)
INIT : à l'ouverture du Patch ou changement de projet Live ou encore changement de tempo manuel dans Live, permette l'initialisation du Tempo Live, Tempo initial et de la Variation (%).
RESET : permets de réinitialiser la Variation (%) et le Tempo modifié uniquement, sans toucher au reste notamment sans changer de projet Live, de tempo d'origine. Cela permets de revenir au tempo d'origine sans avoir à repasser par les bouton ±5%
D'avance merci !
Lorsque le Tempo modifié est différent du tempo initial, si par malheur il ya un click sur INIT, le Tempo modifié (ou Tempo Live dans ce cas) devient le Tempo Initial
Ça me semble être le comportement attendu. Autrement, que devrait-t-il se passer ?
Lors d'un changement de tempo sur Live (changement de projet, changement de tempo manuellement sur un même projet (...) l'action sur le bouton INIT ne suffit pas. Il est nécessaire d' ajouter une action RESET pour rendre le Patch à nouveau utilisable :
Est-ce que INIT doit sauvegarder le tempo actuel comme le tempo initial mais toujours appliquer la variation de X% (basée sur ce nouveau tempo initial) ? Ou est-ce qu'on remet à zéro aussi la variation ?
Dans les deux cas, il semble que le problème vienne du fait lors d'un INIT, la valeur de base du multiplicateur pour la variation ne soit pas mise à jour. [value tempo_initial] n'envoie une valeur que quand il reçoit un bang, d'où le besoin de RESET. Plusieurs manières de résoudre cela, voilà sûrement la plus simple :
le [t b b] après le init permet de s'assurer que [value tempo_initial] soit mis à jour AVANT d'envoyer le bang au reset, qui à son tour va mettre à jour le [* 1.] avec la valeur correcte du nouveau tempo initiale.