Tester si bouton de souris appuyé ?

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

Jouer un son MIDI est je pense la bonne solution

Ton application lit 15 notes verticales de gauche à droite.
Il faut mettre chaque note lu sur un canal différent puis jouer les 15 notes en même temps.

Un exemple avec ce code si dessous qui va jouer l'accord DO MI SOL. Pour cela on va ouvrir 3 canaux avec le même instrument et affecter une fréquence de note à chaque canal.

Code : Tout sélectionner

; erix14 - https://www.purebasic.fr/french/viewtopic.php?t=395 (2004)
;
; Numéro Instrument entre 0 et 127
; Numéro du canal entre 0 et 15
; Note de musique entre 0 et 127
;
;             Do    Do#    Ré    Ré#    Mi    Fa    Fa#    Sol    Sol#    La    La#    Si
; Octave -2   0     1      2     3      4     5     6      7      8       9     10     11
; Octave -1   12    13     14    15     16    17    18     19     20      21    22     23
; Octave  0   24    25     26    27     28    29    30     31     32      33    34     35
; Octave  1   36    37     38    39     40    41    42     43     44      45    46     47
; Octave  2   48    49     50    51     52    53    54     55     56      57    58     59
; Octave  3   60    61     62    63     64    65    66     67     68      69    70     71
; Octave  4   72    73     74    75     76    77    78     79     80      81    82     83
; Octave  5   84    85     86    87     88    89    90     91     92      93    94     95  
; Octave  6   96    97     98    99     100   101   102    103    104     105   106    107
; Octave  7   108   109    110   111    112   113   114    115    116     117   118    119
; Octave  8   120   121    122   123    124   125   126    127
;
; Vélocité avec laquelle la touche (Note) a été enfoncée (entre 0 et 127) ou relâchée
;

Global m_hMidiOut.l ; handle du périphérique de sortie MIDI
Global m_MIDIOpen.b ; 1 = périphérique de sortie MIDI ouvert      0 = non ouvert

Dim NomInstrument.s(127)
NomInstrument(0)   = "Piano à queue"
NomInstrument(1)   = "Piano"
NomInstrument(2)   = "Electric grand piano"
NomInstrument(3)   = "Honky-Tonk"
NomInstrument(4)   = "Electric Piano 1"
NomInstrument(5)   = "Electric Piano 2"
NomInstrument(6)   = "Harpsichord"
NomInstrument(7)   = "Clavinet"
NomInstrument(8)   = "Celesta"
NomInstrument(9)   = "Glockenspiel"
NomInstrument(10)  = "Music Box"
NomInstrument(11)  = "Vibraphone"
NomInstrument(12)  = "Marimba"
NomInstrument(13)  = "Xylophone"
NomInstrument(14)  = "Tubular Bells"
NomInstrument(15)  = "Dulcimer"
NomInstrument(16)  = "Drawbar Organ"
NomInstrument(17)  = "Percussive Organ"
NomInstrument(18)  = "Rock Organ"
NomInstrument(19)  = "Chuch Organ"
NomInstrument(20)  = "Reed Organ"
NomInstrument(21)  = "Accordion"
NomInstrument(22)  = "Harmonica"
NomInstrument(23)  = "Tango Accordion"
NomInstrument(24)  = "Acoustic Guitar (Nylon)"
NomInstrument(25)  = "Acoustic Guitar (Acier)"
NomInstrument(26)  = "Electric Guitar"
NomInstrument(27)  = "Electric Guitar (Clean)"
NomInstrument(28)  = "Electric Guitar (Muted)"
NomInstrument(29)  = "Overdriven Guitar"
NomInstrument(30)  = "Distortion Guitar"
NomInstrument(31)  = "Guitar harmonics"
NomInstrument(32)  = "Acoustic Bass"
NomInstrument(33)  = "Electric Bass"
NomInstrument(34)  = "Electric Bass (Finger)"
NomInstrument(35)  = "Fretless Bass"
NomInstrument(36)  = "Slap Bass 1"
NomInstrument(37)  = "Slap Bass 2"
NomInstrument(38)  = "Synth Bass 1"
NomInstrument(39)  = "Synth Bass 2"
NomInstrument(40)  = "Violon"
NomInstrument(41)  = "Viola"
NomInstrument(42)  = "Cello"
NomInstrument(43)  = "Contrebass"
NomInstrument(44)  = "Tremolo Strings"
NomInstrument(45)  = "Pizzicato Strings"
NomInstrument(46)  = "Orchestral Harp"
NomInstrument(47)  = "Timpani"
NomInstrument(48)  = "String Ensemble 1"
NomInstrument(49)  = "String Ensemble 2"
NomInstrument(50)  = "SynthString 1"
NomInstrument(51)  = "SynthString 2"
NomInstrument(52)  = "Choir Aahs"
NomInstrument(53)  = "Voice Oohs"
NomInstrument(54)  = "Synth Voice"
NomInstrument(55)  = "Orchestra Hit"
NomInstrument(56)  = "Trumpet"
NomInstrument(57)  = "Trombone"
NomInstrument(58)  = "Tuba"
NomInstrument(59)  = "Muted Trumpet"
NomInstrument(60)  = "French Horn"
NomInstrument(61)  = "Brass Section"
NomInstrument(62)  = "SynthBass 1"
NomInstrument(63)  = "SynthBass 2"
NomInstrument(64)  = "Soprano Sax"
NomInstrument(65)  = "Alto Sax"
NomInstrument(66)  = "Tenor Sax"
NomInstrument(67)  = "Bartone Sax"
NomInstrument(68)  = "Oboe"
NomInstrument(69)  = "English Horn"
NomInstrument(70)  = "Bassoon"
NomInstrument(71)  = "Clarinet"
NomInstrument(72)  = "Piccolo"
NomInstrument(73)  = "Flute"
NomInstrument(74)  = "Recorder"
NomInstrument(75)  = "Pan Flute"
NomInstrument(76)  = "Blown Bottle"
NomInstrument(77)  = "Shakuhachi"
NomInstrument(78)  = "Whistle"
NomInstrument(79)  = "Ocarina"
NomInstrument(80)  = "Square"
NomInstrument(81)  = "Sawtooth"
NomInstrument(82)  = "Calliop"
NomInstrument(83)  = "Chiff"
NomInstrument(84)  = "Charang"
NomInstrument(85)  = "Voice"
NomInstrument(86)  = "Fifths"
NomInstrument(87)  = "Bass + Lead"
NomInstrument(88)  = "New Age"
NomInstrument(89)  = "Warm"
NomInstrument(90)  = "Polysynth"
NomInstrument(91)  = "Choir"
NomInstrument(92)  = "Bowed"
NomInstrument(93)  = "Metallic"
NomInstrument(94)  = "Halo"
NomInstrument(95)  = "Sweep"
NomInstrument(96)  = "Rain"
NomInstrument(97)  = "Soundtrack"
NomInstrument(98)  = "Crystal"
NomInstrument(99)  = "Atmosphere"
NomInstrument(100) = "Brightness"
NomInstrument(101) = "Goblins"
NomInstrument(102) = "Echoes"
NomInstrument(103) = "Sci-Fi"
NomInstrument(104) = "Sitar Ethnik"
NomInstrument(105) = "Banjo"
NomInstrument(106) = "Shamisen"
NomInstrument(107) = "Koto"
NomInstrument(108) = "Kalimba"
NomInstrument(109) = "Bag Pipe"
NomInstrument(110) = "Fiddle"
NomInstrument(111) = "Shanai"
NomInstrument(112) = "Tinkle Bell"
NomInstrument(113) = "Agogo"
NomInstrument(114) = "Steel Drums"
NomInstrument(115) = "Woodblock"
NomInstrument(116) = "Taiko Drum"
NomInstrument(117) = "Melodic Tom"
NomInstrument(118) = "Synth Drum"
NomInstrument(119) = "Reverse Cymbal"
NomInstrument(120) = "Guitar Fret. Noise"
NomInstrument(121) = "Breath Noise"
NomInstrument(122) = "Seashore"
NomInstrument(123) = "Bird Tweet"
NomInstrument(124) = "Telephone Ring"
NomInstrument(125) = "Helicopter"
NomInstrument(126) = "Applause"
NomInstrument(127) = "Gun Shot"
;-----------------------------------------------------------------------------------------------------------
Procedure SendMIDIMessage(nStatus.l,nCanal.l,nData1.l,nData2.l)
  dwFlags.l = nStatus | nCanal | (nData1 << 8) | (nData2 << 16)
  temp.l = midiOutShortMsg_(m_hMidiOut,dwFlags);
  If temp<>0 
    MessageRequester("Problème", "Erreur dans l'envoi du message MIDI",0)
  EndIf
EndProcedure
;-----------------------------------------------------------------------------------------------------------
Procedure MIDIOpen()
  If m_MIDIOpen = 0
    If midiOutOpen_(@m_hMidiOut,MIDIMAPPER,0,0,0) <> 0 
      MessageRequester("Problème", "Impossible d'ouvrir le périphérique MIDI",0)
    Else
      SendMIDIMessage($c0,0,0,0)
      m_MIDIOpen = 1
    EndIf
  EndIf
EndProcedure
;-----------------------------------------------------------------------------------------------------------
Procedure PlayNoteMIDI(Canal.b,Note.b,VelociteDown.b,VelociteUp.b)
  If m_MIDIOpen = 0
    MIDIOpen()
  EndIf
  If m_MIDIOpen = 1
    SendMIDIMessage($80 | Canal,0,Note,VelociteDown)
    SendMIDIMessage($90 | Canal,0,Note,VelociteUp)
  EndIf          
EndProcedure
;-----------------------------------------------------------------------------------------------------------
Procedure ChargeInstrument(Canal.b,Instrument.b)
  If m_MIDIOpen = 0
    MIDIOpen()
  EndIf
  If m_MIDIOpen = 1
    SendMIDIMessage($c0 | Canal,0,Instrument,0)
  EndIf          
EndProcedure

; Exemple 

VelocityDown = 100
VelocityUp   = 60
Instrument   = 5 ;Piano

ChargeInstrument(1, Instrument)
ChargeInstrument(2, Instrument)
ChargeInstrument(3, Instrument)

; Jouer l'accord DO MI SOL
PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(2, 76, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(3, 79, VelocityDown, VelocityUp) ;Sol sur le canal 3


MessageRequester("Information","C'est fini. Il était beau cet accord ;)")

Bonne lecture. 2h15 du matin je vais me coucher.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Stan_fr
Messages : 84
Inscription : mar. 07/mars/2023 20:01
Localisation : NANTES

Re: Tester si bouton de souris appuyé ?

Message par Stan_fr »

falsam a écrit : mer. 29/mars/2023 1:11 Jouer un son MIDI est je pense la bonne solution

Ton application lit 15 notes verticales de gauche à droite.
Il faut mettre chaque note lu sur un canal différent puis jouer les 15 notes en même temps.

Un exemple avec ce code si dessous qui va jouer l'accord DO MI SOL. Pour cela on va ouvrir 3 canaux avec le même instrument et affecter une fréquence de note à chaque canal.
Bonne lecture. 2h15 du matin je vais me coucher.
YES !!! MERCI

Là je suis dans un domaine que je connais en tant que musicien !
J'avais cherché comment envoyer du MIDI en Pb mais pas trouvé :?:

Pour jouer un instrument unique tu n'as pas besoin de changer de canal midi tu peux jouer un tas de notes !

En tout cas GRAND MERCI à toi.

Merci aussi à Ar-S pour ses suggestions.
.
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

Stan_fr a écrit : mer. 29/mars/2023 11:59 Pour jouer un instrument unique tu n'as pas besoin de changer de canal midi tu peux jouer un tas de notes !
Tout à fait d'accord avec toi.

Par contre pour jouer 15 notes simultanées avec le même instrument comment tu fais avec PureBasic ?

N'ayant pas trouver la réponse, j'avais imaginé de jouer ces 15 notes simultanés sur 15 canaux avec le même instrument.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Stan_fr
Messages : 84
Inscription : mar. 07/mars/2023 20:01
Localisation : NANTES

Re: Tester si bouton de souris appuyé ?

Message par Stan_fr »

falsam a écrit : mer. 29/mars/2023 12:39
Stan_fr a écrit : mer. 29/mars/2023 11:59 Pour jouer un instrument unique tu n'as pas besoin de changer de canal midi tu peux jouer un tas de notes !
Tout à fait d'accord avec toi.

Par contre pour jouer 15 notes simultanées avec le même instrument comment tu fais avec PureBasic ?

N'ayant pas trouver la réponse, j'avais imaginé de jouer ces 15 notes simultanés sur 15 canaux avec le même instrument.
Tu changes ton code :

Code : Tout sélectionner

; Jouer l'accord DO MI SOL
PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(2, 76, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(3, 79, VelocityDown, VelocityUp) ;Sol sur le canal 3
en

Code : Tout sélectionner

; Jouer l'accord DO MI SOL.....
PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 76, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(1, 79, VelocityDown, VelocityUp) ;Sol sur le canal 3
PlayNoteMIDI(1, 82, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 86, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(1, 89, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 56, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(1, 59, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 56, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(1, 79, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 46, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(1, 49, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 66, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(1, 39, VelocityDown, VelocityUp) ;Sol sur le canal 3

MessageRequester("Information","C'est fini. Il était beau cet accord ;)")

Tout est joué sur le canal 1 ; Je ne sais pas si il y a 15 notes, mais le synthé MIDI de Windows fonctionne en Asynchrone.
Utiliser 15 canaux n'a d'intérêt que si tu veux 15 sons (au sens instruments) différents : un piano, un sax, etc.

par exemple :

Code : Tout sélectionner

ChargeInstrument(1, Instrument)
ChargeInstrument(2, 1)  ; autre instrument
ChargeInstrument(3, Instrument)

; Jouer l'accord DO MI SOL.....
PlayNoteMIDI(1, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 76, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(1, 79, VelocityDown, VelocityUp) ;Sol sur le canal 3
PlayNoteMIDI(1, 82, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(1, 86, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(2, 89, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(2, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(2, 56, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(2, 59, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(2, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(2, 56, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(2, 79, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(2, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(2, 46, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(2, 49, VelocityDown, VelocityUp) ;Sol sur le canal 3PlayNoteMIDI(2, 72, VelocityDown, VelocityUp) ;Do sur le canal 1
PlayNoteMIDI(2, 66, VelocityDown, VelocityUp) ;Mi sur le canal 2
PlayNoteMIDI(2, 39, VelocityDown, VelocityUp) ;Sol sur le canal 3
Et tu verras que tu ne coupes pas la note dans ton programme si tu prends un instrument comme un orgue ! :D
(en fait tu la coupes avant de la jouer, puis tu la joues ! : si tu enlèves le

Code : Tout sélectionner

SendMIDIMessage($80 | Canal,0,Note,VelociteDown))
ça ne change pas son comportement.

Mais ça je sais faire... : envoyer un ALLNOTEOFF lorsque qu'on change de colonne, ou un un NOTE OFF à chaque plot encore actif....
.
Stan_fr
Messages : 84
Inscription : mar. 07/mars/2023 20:01
Localisation : NANTES

Re: Tester si bouton de souris appuyé ?

Message par Stan_fr »

Bon maintenant, il ne me reste plus qu'à comprendre comment désélectionner les plots dans ton programme (j'ai du mal)
et remplacer le Beep_(\freq, 100) par un Note On MIDI(SendMIDIMessage($90 | Canal,0,Note,VelociteUp), mais ça je devrais y arriver c'est pratiquement du C et là je sais faire.
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

Stan_fr a écrit : mer. 29/mars/2023 15:32 remplacer le Beep_(\freq, 100) par un Note On MIDI(SendMIDIMessage($90 | Canal,0,Note,VelociteUp),

Code : Tout sélectionner

EnableExplicit

Enumeration window
  #mf
EndEnumeration

Enumeration gadget
  #mfGrid  
EndEnumeration

Enumeration misc
  #timer  
EndEnumeration

Structure Plot
  ; Coordonnée coin haut gauche 
  x0.i
  y0.i
  
  ; Coordonnée coin bas droit
  x1.i
  y1.i
  
  ; Chaque plot est associé à une fréquence
  freq.i
  
  ; Le plot est sélectionné (ou pas)
  isSelect.b
EndStructure

; Flag début d'écoute. Actif au premier plot musical selectionné
Global Flag.b

; Construction du grid composé de plot (16x16)
Global Dim Grid.Plot(15,15)
Global Dim Freqencies(15)

; Définition des couleurs de plot 
Global PlotColorInactif = RGB(105, 105, 105)
Global PlotColorActif = RGB(245, 245, 245)
Global PlotColorPlay  = RGB(255, 105, 180)

; MIDI
Global m_hMidiOut.l ; handle du périphérique de sortie MIDI
Global m_MIDIOpen.b ; 1 = périphérique de sortie MIDI ouvert      0 = non ouvert
Global VelocityDown = 100
Global VelocityUp = 50

;Sommaire
Declare Start()
Declare InitFrequencies()
Declare DrawGrid()
Declare PlayGrid()
Declare onPlot()

Declare SendMIDIMessage(nStatus.l,nCanal.l,nData1.l,nData2.l)
Declare MIDIOpen()
Declare PlayNoteMIDI(Canal.b,Note.b,VelociteDown.b,VelociteUp.b)
Declare ChargeInstrument(Canal.b,Instrument.b)

Declare Exit()

Start()

Procedure Start()
  Protected MarginLeft = (800 - (16*22))/2, MarginTop = (600 - (16*22))/2 
  Protected x, y, Plot 
  
  ChargeInstrument(1, 11) ; Piano sur canal 1
  
  InitFrequencies()
  
  OpenWindow(#mf, 0, 0, 800, 600, "ToneMatrix Redux", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  SetWindowColor(#mf, RGB(0, 0, 0))
  
  ; Installation de la grille 
  CanvasGadget(#mfGrid, MarginLeft, MarginTop, 16*24, 16*24, #PB_Canvas_ClipMouse)
  DrawGrid()
  
  ; Ajout d'un timer pour jouer les notes 
  AddWindowTimer(#mf, #Timer, 1) 
  
  ; Déclencheur
  BindGadgetEvent(#mfGrid, @onPlot())
  BindEvent(#PB_Event_Timer, @PLayGrid())
  BindEvent(#PB_Event_CloseWindow, @Exit())
  
  ; Loop
  Repeat : WaitWindowEvent(0) : ForEver   
EndProcedure

Procedure InitFrequencies()
  Protected n, tone = 36 ;Départ à l'octave 1
  For n = 0 To 15
    Freqencies(15-n) = tone
    tone + 1
  Next
EndProcedure

; Dessiner le grid 
; Initialiser la fréquence de chaque plot
Procedure DrawGrid()
  Protected x, y
  
  ; Fond du grid
  StartDrawing(CanvasOutput(#mfGrid))
  Box(0, 0, 16*24, 16*24, RGB(0, 0, 0))
  
  ; Dessin des 16x16 plots
  For x = 0 To 15
    For y = 0 To 15
      
      With Grid(x,y)
        \x0 = x*24
        \y0 = y*24
        \x1 = \x0 + 20
        \y1 = \y0 + 20
        
        \freq = Freqencies(y)        
        
        Box(Grid(x,y)\x0, Grid(x,y)\y0, 20, 20, PlotColorInactif)
      EndWith 
    Next
  Next
  StopDrawing()
EndProcedure

; Jouer la fréquence associé au plot
Procedure PlayGrid()
  Static x, y
  
  If flag 
    With Grid(x,y)
      If \isSelect 
        StartDrawing(CanvasOutput(#mfGrid))
        Box(\x0, \y0, 20, 20, PlotColorPlay)
        StopDrawing()   
        
        ;Beep_(\freq, 100)
        PlayNoteMIDI(1, \freq, VelocityDown, VelocityUp)
        StartDrawing(CanvasOutput(#mfGrid))
        Box(\x0, \y0, 20, 20, PlotColorActif)
        StopDrawing()   
      EndIf
    EndWith
    
    ; Balayage de haut en bas (Axe y)
    ; Puis de gauche à froite (Axe X)
    y+1
    
    ; La derniere ligne est traitée 
    If y = 16
      y = 0
      x + 1
    EndIf
    
    ; La derniéere colonne est traitée
    If x = 16
      x = 0
      y = 0
    EndIf
  EndIf 
EndProcedure

; Un plot est sélectionné 
; - On passe dessus avec le clic gauche de la souris préssé
; - Quand on le clic (Non traité dans cet exemple)
; 
; La déselection d'un plot n'est pas traité
Procedure onPlot()
  Protected x, y
  Protected px = GetGadgetAttribute(#mfGrid, #PB_Canvas_MouseX)
  Protected py = GetGadgetAttribute(#mfGrid, #PB_Canvas_MouseY)
  
  flag = #True
  
  ; La souris est en mouvement et la touche gauche de la soutis est préssée
  If (EventType() = #PB_EventType_MouseMove  And 
      GetGadgetAttribute(#mfGrid, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
    For x = 0 To 15
      For y = 0 To 15
        With Grid(x,y)
          If px >= \x0 And py>= \y0 And px <= \x1 And py <= \y1          
            StartDrawing(CanvasOutput(#mfGrid))
            Box(\x0, \y0, 20, 20, PlotColorActif)
            StopDrawing()
            
            ; Le plot est sélectionné  
            \isSelect = #True
          EndIf
        EndWith
      Next 
    Next   
  EndIf      
EndProcedure

;-
Procedure SendMIDIMessage(nStatus.l,nCanal.l,nData1.l,nData2.l)
  Protected dwFlags.l = nStatus | nCanal | (nData1 << 8) | (nData2 << 16)
  Protected temp.l = midiOutShortMsg_(m_hMidiOut,dwFlags);
  If temp<>0 
    MessageRequester("Problème", "Erreur dans l'envoi du message MIDI",0)
  EndIf
EndProcedure

Procedure MIDIOpen()
  If m_MIDIOpen = 0
    If midiOutOpen_(@m_hMidiOut,0,0,0,0) <> 0 
      MessageRequester("Problème", "Impossible d'ouvrir le périphérique MIDI",0)
    Else
      SendMIDIMessage($c0,0,0,0)
      m_MIDIOpen = 1
    EndIf
  EndIf
EndProcedure

Procedure PlayNoteMIDI(Canal.b,Note.b,VelociteDown.b,VelociteUp.b)
  If m_MIDIOpen = 0
    MIDIOpen()
  EndIf
  If m_MIDIOpen = 1
    SendMIDIMessage($80 | Canal,0,Note,VelociteDown)
    SendMIDIMessage($90 | Canal,0,Note,VelociteUp)
  EndIf          
EndProcedure

Procedure ChargeInstrument(Canal.b,Instrument.b)
  If m_MIDIOpen = 0
    MIDIOpen()
  EndIf
  If m_MIDIOpen = 1
    SendMIDIMessage($c0 | Canal,0,Instrument,0)
  EndIf          
EndProcedure
;-
Procedure Exit()
  End
EndProcedure
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Stan_fr
Messages : 84
Inscription : mar. 07/mars/2023 20:01
Localisation : NANTES

Re: Tester si bouton de souris appuyé ?

Message par Stan_fr »

falsam a écrit : mer. 29/mars/2023 16:54
Stan_fr a écrit : mer. 29/mars/2023 15:32 remplacer le Beep_(\freq, 100) par un Note On MIDI(SendMIDIMessage($90 | Canal,0,Note,VelociteUp),

Code : Tout sélectionner

EnableExplicit

Enumeration window
  #mf
EndEnumeration

Enumeration gadget
  #mfGrid  
EndEnumeration

Enumeration misc
  #timer  
EndEnumeration

Structure Plot
  ; Coordonnée coin haut gauche 
  x0.i
  y0.i
  
  ; Coordonnée coin bas droit
  x1.i
  y1.i
  
  ; Chaque plot est associé à une fréquence
  freq.i
  
  ; Le plot est sélectionné (ou pas)
  isSelect.b
EndStructure

; Flag début d'écoute. Actif au premier plot musical selectionné
Global Flag.b

; Construction du grid composé de plot (16x16)
Global Dim Grid.Plot(15,15)
Global Dim Freqencies(15)

; Définition des couleurs de plot 
Global PlotColorInactif = RGB(105, 105, 105)
Global PlotColorActif = RGB(245, 245, 245)
Global PlotColorPlay  = RGB(255, 105, 180)

; MIDI
Global m_hMidiOut.l ; handle du périphérique de sortie MIDI
Global m_MIDIOpen.b ; 1 = périphérique de sortie MIDI ouvert      0 = non ouvert
Global VelocityDown = 100
Global VelocityUp = 50

;Sommaire
Declare Start()
Declare InitFrequencies()
Declare DrawGrid()
Declare PlayGrid()
Declare onPlot()

Declare SendMIDIMessage(nStatus.l,nCanal.l,nData1.l,nData2.l)
Declare MIDIOpen()
Declare PlayNoteMIDI(Canal.b,Note.b,VelociteDown.b,VelociteUp.b)
Declare ChargeInstrument(Canal.b,Instrument.b)

Declare Exit()

Start()

Procedure Start()
  Protected MarginLeft = (800 - (16*22))/2, MarginTop = (600 - (16*22))/2 
  Protected x, y, Plot 
  
  ChargeInstrument(1, 11) ; Piano sur canal 1
  
  InitFrequencies()
  
  OpenWindow(#mf, 0, 0, 800, 600, "ToneMatrix Redux", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  SetWindowColor(#mf, RGB(0, 0, 0))
  
  ; Installation de la grille 
  CanvasGadget(#mfGrid, MarginLeft, MarginTop, 16*24, 16*24, #PB_Canvas_ClipMouse)
  DrawGrid()
  
  ; Ajout d'un timer pour jouer les notes 
  AddWindowTimer(#mf, #Timer, 1) 
  
  ; Déclencheur
  BindGadgetEvent(#mfGrid, @onPlot())
  BindEvent(#PB_Event_Timer, @PLayGrid())
  BindEvent(#PB_Event_CloseWindow, @Exit())
  
  ; Loop
  Repeat : WaitWindowEvent(0) : ForEver   
EndProcedure

Procedure InitFrequencies()
  Protected n, tone = 36 ;Départ à l'octave 1
  For n = 0 To 15
    Freqencies(15-n) = tone
    tone + 1
  Next
EndProcedure

; Dessiner le grid 
; Initialiser la fréquence de chaque plot
Procedure DrawGrid()
  Protected x, y
  
  ; Fond du grid
  StartDrawing(CanvasOutput(#mfGrid))
  Box(0, 0, 16*24, 16*24, RGB(0, 0, 0))
  
  ; Dessin des 16x16 plots
  For x = 0 To 15
    For y = 0 To 15
      
      With Grid(x,y)
        \x0 = x*24
        \y0 = y*24
        \x1 = \x0 + 20
        \y1 = \y0 + 20
        
        \freq = Freqencies(y)        
        
        Box(Grid(x,y)\x0, Grid(x,y)\y0, 20, 20, PlotColorInactif)
      EndWith 
    Next
  Next
  StopDrawing()
EndProcedure

; Jouer la fréquence associé au plot
Procedure PlayGrid()
  Static x, y
  
  If flag 
    With Grid(x,y)
      If \isSelect 
        StartDrawing(CanvasOutput(#mfGrid))
        Box(\x0, \y0, 20, 20, PlotColorPlay)
        StopDrawing()   
        
        ;Beep_(\freq, 100)
        PlayNoteMIDI(1, \freq, VelocityDown, VelocityUp)
        StartDrawing(CanvasOutput(#mfGrid))
        Box(\x0, \y0, 20, 20, PlotColorActif)
        StopDrawing()   
      EndIf
    EndWith
    
    ; Balayage de haut en bas (Axe y)
    ; Puis de gauche à froite (Axe X)
    y+1
    
    ; La derniere ligne est traitée 
    If y = 16
      y = 0
      x + 1
    EndIf
    
    ; La derniéere colonne est traitée
    If x = 16
      x = 0
      y = 0
    EndIf
  EndIf 
EndProcedure

; Un plot est sélectionné 
; - On passe dessus avec le clic gauche de la souris préssé
; - Quand on le clic (Non traité dans cet exemple)
; 
; La déselection d'un plot n'est pas traité
Procedure onPlot()
  Protected x, y
  Protected px = GetGadgetAttribute(#mfGrid, #PB_Canvas_MouseX)
  Protected py = GetGadgetAttribute(#mfGrid, #PB_Canvas_MouseY)
  
  flag = #True
  
  ; La souris est en mouvement et la touche gauche de la soutis est préssée
  If (EventType() = #PB_EventType_MouseMove  And 
      GetGadgetAttribute(#mfGrid, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton)
    For x = 0 To 15
      For y = 0 To 15
        With Grid(x,y)
          If px >= \x0 And py>= \y0 And px <= \x1 And py <= \y1          
            StartDrawing(CanvasOutput(#mfGrid))
            Box(\x0, \y0, 20, 20, PlotColorActif)
            StopDrawing()
            
            ; Le plot est sélectionné  
            \isSelect = #True
          EndIf
        EndWith
      Next 
    Next   
  EndIf      
EndProcedure

;-
Procedure SendMIDIMessage(nStatus.l,nCanal.l,nData1.l,nData2.l)
  Protected dwFlags.l = nStatus | nCanal | (nData1 << 8) | (nData2 << 16)
  Protected temp.l = midiOutShortMsg_(m_hMidiOut,dwFlags);
  If temp<>0 
    MessageRequester("Problème", "Erreur dans l'envoi du message MIDI",0)
  EndIf
EndProcedure

Procedure MIDIOpen()
  If m_MIDIOpen = 0
    If midiOutOpen_(@m_hMidiOut,0,0,0,0) <> 0 
      MessageRequester("Problème", "Impossible d'ouvrir le périphérique MIDI",0)
    Else
      SendMIDIMessage($c0,0,0,0)
      m_MIDIOpen = 1
    EndIf
  EndIf
EndProcedure

Procedure PlayNoteMIDI(Canal.b,Note.b,VelociteDown.b,VelociteUp.b)
  If m_MIDIOpen = 0
    MIDIOpen()
  EndIf
  If m_MIDIOpen = 1
    SendMIDIMessage($80 | Canal,0,Note,VelociteDown)
    SendMIDIMessage($90 | Canal,0,Note,VelociteUp)
  EndIf          
EndProcedure

Procedure ChargeInstrument(Canal.b,Instrument.b)
  If m_MIDIOpen = 0
    MIDIOpen()
  EndIf
  If m_MIDIOpen = 1
    SendMIDIMessage($c0 | Canal,0,Instrument,0)
  EndIf          
EndProcedure
;-
Procedure Exit()
  End
EndProcedure
Ça marche mieux mais : on ne désélectionne toujours pas en recliquant, je suppose que ça se résout facilement...

Et les sons ne s'éteignent jamais (essaie avec un son long, comme l'instrument 70)
On peut le faire, en fin de grille,en modifiant PlayGrid :

Code : Tout sélectionner

Procedure PlayGrid()
  Static x, y
  
  If flag 
    With Grid(x,y)
      If \isSelect 
        StartDrawing(CanvasOutput(#mfGrid))
        Box(\x0, \y0, 20, 20, PlotColorPlay)
        StopDrawing()   
        
        ;Beep_(\freq, 100)
        PlayNoteMIDI(1, \freq, VelocityDown, VelocityUp)
        StartDrawing(CanvasOutput(#mfGrid))
        Box(\x0, \y0, 20, 20, PlotColorActif)
        StopDrawing()   
      EndIf
    EndWith
    
    ; Balayage de haut en bas (Axe y)
    ; Puis de gauche à froite (Axe X)
    y+1
        
    ; La derniere ligne est traitée 
    If y = 16
      y = 0
      x + 1
 ;     SendMIDIMessage($B0 | Canal,0,Note,VelociteDown)
    EndIf
    
    ; La derniéere colonne est traitée
    If x = 16
      x = 0
      y = 0

  Delay(500) ; à moduler en fonction du tempo
    ;Coupe toutes les notes
         For index=0 To 128
        
        SendMIDIMessage($80 | 1,0,index,0)
        Next
    EndIf
  EndIf 
  
EndProcedure
C'est mieux mais pas entièrement satisfaisant : il faudrait pouvoir à chaque colonne, mais ça devient bloquant (ça ralentit l'allumage des plots), il faudrait avoir un delay non bloquant 'qui envoie l'analogue d'une interrupt*), ou un tracé Asynchrone. (Thread ?).

*désolé je raisonne en habitué de microcontrôleurs en RT.
.
Stan_fr
Messages : 84
Inscription : mar. 07/mars/2023 20:01
Localisation : NANTES

Re: Tester si bouton de souris appuyé ?

Message par Stan_fr »

J'ai eu l'idée de mettre un deuxième timer et faire un "dispatcheur" d'événements timer, comme callback :

si timer original on lance le callback original,
sinon ... rien pour l'instant
.

Code : Tout sélectionner

Declare TimeManage(a,b,c,T_Event)
....
....
  ; Ajout d'un timer pour jouer les notes 
  AddWindowTimer(#mf, #Timer, 1) 
  AddWindowTimer(#mf, #Timer2, 500) 
  ; Déclencheur
  BindGadgetEvent(#mfGrid, @onPlot())
  BindEvent(#PB_Event_Timer, @TimeManage(),#mf,#PB_All,#PB_All )
  BindEvent(#PB_Event_CloseWindow, @Exit())
  
  ; Loop
  Repeat : WaitWindowEvent(0) : ForEver   
EndProcedure

Procedure TimeManage(a,b,c,T_Event)
  
  If T_Event = #PB_Event_Timer And EventTimer() = #Timer
    MessageRequester("","ok")
    Playgrid()
  Else
  EndIf
EndProcedure
  
Ça passe au syntax check

Par contre à la compil (F5), message d'erreur :

[ERROR] The Procedure specified in '@Callback()' does not have the required argument or returntype.

Et ça se plante. :roll:

HELP : Où est mon erreur :?: :?:
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

Stan_fr a écrit : jeu. 30/mars/2023 5:28 BindEvent(#PB_Event_Timer, @TimeManage(),#mf,#PB_All,#PB_All )
Tu ne peux pas faire appel à une procédure contenant des paramètres.

C'est indiqué dans la documentation.
@Callback() La procédure à appeler lorsque l'évènement se produit. Elle doit être déclarée comme ceci:
Procedure EventHandler()
; Du code ici...
EndProcedure
Pour rappel. Si tu as un doute sur une fonctionnalité, place le curseur sur la fonction qui te pose problème et presse la touche F1 😉
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Stan_fr
Messages : 84
Inscription : mar. 07/mars/2023 20:01
Localisation : NANTES

Re: Tester si bouton de souris appuyé ?

Message par Stan_fr »

Tu as sans doute raison, mais ce n'est pas clair dans l'aide ;

Par exemple pour SetWindowCallback()
On peut lire :

Code : Tout sélectionner

La procédure de Callback doit avoir 4 paramètres et se présente sous la forme suivante: 

  Procedure MaProcedureCallback(WindowID, Message, WParam, LParam)
    Resultat = #PB_ProcessPureBasicEvents
    ;
    ; Votre code ici
    ;
    ProcedureReturn Resultat
  EndProcedure


Code : Tout sélectionner

  Procedure WinCallback(hWnd, uMsg, WParam, LParam) 
 ; Windows remplit automatiquement les paramètres.
    ; Ces paramètre sont utilisable dans le code de la callback.
    
    If uMsg = #WM_SIZE 
      Select WParam 
        Case #SIZE_MINIMIZED 
          Debug "La fenêtre est minimisée" 
        Case #SIZE_RESTORED 
          Debug "La fenêtre est rétablie" 
        Case #SIZE_MAXIMIZED 
          Debug "La fenêtre est agrandie" 
      EndSelect 
    EndIf 
  
    ProcedureReturn #PB_ProcessPureBasicEvents 
  EndProcedure 
  
  
  If OpenWindow(0, 0, 0, 200, 100, "Messages", #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget) 
    
    SetWindowCallback(@WinCallback())    ; active la callback
    
    Repeat 
      Select WaitWindowEvent() 
        Case #PB_Event_CloseWindow 
          End 
      EndSelect 
    ForEver 
    
  EndIf 
  
Mais concrètement est-il possible de faire ce que je voulais : une callback qui aiguillerait vers un traitement ou un autre en fonction du timer qui l'a déclenché, au final savoir quel timer l'a "appelée" ?

Ou même faire l'aiguillage dans la fonction d'origine ?
.
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

Stan_fr a écrit : jeu. 30/mars/2023 11:13 Tu as sans doute raison, mais ce n'est pas clair dans l'aide ;
Comment ça sans doute ? Pas de doute possible. J'ai raison :mrgreen:

■ Dans un commentaire précèdent tu as demandé ou était le souci dans ce code.

Code : Tout sélectionner

Declare TimeManage(a,b,c,T_Event)
....
....
  ; Ajout d'un timer pour jouer les notes 
  AddWindowTimer(#mf, #Timer, 1) 
  AddWindowTimer(#mf, #Timer2, 500) 
  ; Déclencheur
  BindGadgetEvent(#mfGrid, @onPlot())
  BindEvent(#PB_Event_Timer, @TimeManage(),#mf,#PB_All,#PB_All )
  BindEvent(#PB_Event_CloseWindow, @Exit())
  
  ; Loop
  Repeat : WaitWindowEvent(0) : ForEver   
EndProcedure

Procedure TimeManage(a,b,c,T_Event)
  
  If T_Event = #PB_Event_Timer And EventTimer() = #Timer
    MessageRequester("","ok")
    Playgrid()
  Else
  EndIf
EndProcedure
 
■ Ton BindEvent fait appel à ta procédure TimeManage()

Code : Tout sélectionner

BindEvent(#PB_Event_Timer, @TimeManage(),#mf,#PB_All,#PB_All )
■ Ta procédure TimeManager() est déclarée comme ceci.

Code : Tout sélectionner

Procedure TimeManage(a,b,c,T_Event)
:idea: Je t'ai répondu qu'un BindEvent() ne peut pas faire appel à une procédure paramétrée.
Stan_fr a écrit : jeu. 30/mars/2023 11:13 mais ce n'est pas clair dans l'aide
Si si, l'aide est clair à ce sujet.
Syntaxe

BindGadgetEvent(#Gadget, @Callback() [, TypeEvenement])
Description

Ajoute un évènement d'un gadget à la liste des évènements de la fenêtre.
Cet évènement est lié à la callback de la fenêtre.
Arguments

#Gadget Le gadget à utiliser.
@Callback() La procédure à appeler lorsque l'évènement se produit.

:arrow: Elle doit être déclarée comme ceci:
Procedure EventHandler()
; Code ici...
EndProcedure


EventGadget(), EventWindow(), EventMenu(), EventType() et EventData() sont disponibles pour obtenir plus d'informations sur l'évènement.

Note: WindowEvent() et WaitWindowEvent() ne devraient jamais être appelées à l'intérieur du Callback(), car ça peut verrouiller un programme ou occasionner un comportement erroné.
TypeEvenement (optionnel) Le type d'évènement à ajouter.

#PB_All peut être utilisé pour lier tous les types d'évènements.

- Pour une liste complète des types pris en charge, voir EventType().

Valeur de retour

Aucune.
Si Fred le dit, c'est qu'il faut faire comme ça 😁
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

Stan_fr a écrit : jeu. 30/mars/2023 11:13 Mais concrètement est-il possible de faire ce que je voulais : une callback qui aiguillerait vers un traitement ou un autre en fonction du timer qui l'a déclenché
Whaou !! j'ai compris que tu voudrais qu'un callback initialisé par un SetWindowCallback() déclenche une action en fonction d'un timer initialisé par un AddWindowTimer() qui l'aurait déclenché. Tu serais pas un peu tordu ? ou alors c'est moi :mrgreen:
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

En espérant que j'ai compris ta demande. Compatible Windows uniquement.

Code : Tout sélectionner

Enumeration window
  #mf
EndEnumeration

Enumeration gadget
EndEnumeration

Enumeration misc
  #Timer0
  #Timer1
EndEnumeration


;Sommaire
Declare Start()
Declare MyCallBack(WindowID, Message, WParam, LParam)
Declare Exit()

Start()

Procedure Start()
  OpenWindow(#mf, 0, 0, 800, 600, "Callback", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  SetWindowCallback(@MyCallBack())
  AddWindowTimer(#mf, #Timer0, 1000) 
  AddWindowTimer(#mf, #Timer1, 500)
  
  ; Déclencheur
  BindEvent(#PB_Event_CloseWindow, @Exit())
  
  ; Loop
  Repeat : WaitWindowEvent() : ForEver   
EndProcedure

Procedure MyCallBack(WindowID, Message, WParam, LParam)  
  Select Message
    Case #WM_TIMER
      Select WParam
        Case #Timer0
          Debug "Timer 0"
        Case #Timer1
          Debug "Timer 1"
      EndSelect
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure

Procedure Exit()
  End
EndProcedure
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7317
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Tester si bouton de souris appuyé ?

Message par falsam »

Stan_fr a écrit : mer. 29/mars/2023 19:31 Ça marche mieux mais : on ne désélectionne toujours pas en recliquant, je suppose que ça se résout facilement...
Regarde ce lien viewtopic.php?t=18926
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Stan_fr
Messages : 84
Inscription : mar. 07/mars/2023 20:01
Localisation : NANTES

Re: Tester si bouton de souris appuyé ?

Message par Stan_fr »

falsam a écrit : jeu. 30/mars/2023 11:52
Stan_fr a écrit : jeu. 30/mars/2023 11:13 Mais concrètement est-il possible de faire ce que je voulais : une callback qui aiguillerait vers un traitement ou un autre en fonction du timer qui l'a déclenché
Whaou !! j'ai compris que tu voudrais qu'un callback initialisé par un SetWindowCallback() déclenche une action en fonction d'un timer initialisé par un AddWindowTimer() qui l'aurait déclenché. Tu serais pas un peu tordu ? ou alors c'est moi :mrgreen:
Damned je suis fait ! :oops: Je suis tordu :mrgreen:

C'est peut être que je m'explique mal, l'idée est que :

- la gestion de la souris (bouton appuyé, déplacement...) est rapide (si tu enlèves l'envoi d'une commande midi ça va assez vite),
- l'envoi de 15 commandes Note ON en MIDI est suffisamment rapide pour que l'accord soit perçu comme un accord et pas un arpège très rapide,

Si on mixe la gestion des deux, on entend des notes décalées au point qu'une "barre verticale" de 4 notes semble jouée plus vite que deux notes éloignées (essaie avec deux notes sur la même colonne, une sur la première ligne, l'autre sur la dernière et une barre....)

d'où l’idée (aussi sotte que grenue), que si on pouvait gérer les deux de manière indépendante ça pourrait marcher mieux !

L'idée d'un aiguillage dans un callback n'est peut être pas la bonne, mais je vois ces procedures "bindés" comme des gestionnaire d'interrupts, qui on déjà été aiguillées (puisqu'on peut avoir plusieurs callback pour gérer des events différents.

Il n'est pas question pour moi minuscule padawan de contester Fred ou falsam !

GÉNIAL LA GESTION DE LA GRILLE !
.
Répondre