MIDI PLAYER WPF VB 2008

cs_EBArtSoft Messages postés 4525 Date d'inscription dimanche 29 septembre 2002 Statut Modérateur Dernière intervention 22 avril 2019 - 8 juil. 2008 à 22:54
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016 - 10 nov. 2008 à 12:25
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/47259-midi-player-wpf-vb-2008

Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
10 nov. 2008 à 12:25
Pour plus de clarté :

Les MidiEvents Notes OFF n'existent pas dans la structure objet.
Ils vont être créés lors de l'envoie d'un Msg Note_On dans une Track temporaire et positionné sur le Tick qui correspont au Tick de la Note_On + la durée de la Note_On.

C'est un mécanisme à la vollée !

Voilà

Afyn - Navedac
Ricomat Messages postés 3 Date d'inscription vendredi 7 mars 2003 Statut Membre Dernière intervention 10 novembre 2008
10 nov. 2008 à 12:19
merci pour ton envoi :).

Je vois que tu gères maintenant un piste NoteOffTrack :), qui te sert à stopper les NOTE ON en cours.
Si l'on commente les lignes suivantes, les sons ne s'arrêtent pas, je pense que tu peux enlever le MidiOutReset qui se trouve un peu avant dans ton code. le MidiOutReset n'a pas vraiment l'air de fonctionner sous vista. sinon bien vu ;).

' Reset le MIDI
For Each Tck As Tick In NoteOffTrack.Ticks
For Each Evt As MidiEvent In Tck.MidiEvents
Call WinMM.midiOutShortMsg(hMidiOut, Evt.Msg)
Next
Next
NoteOffTrack.Clear()

Pour tes class Track and co, dès que j'ai un peu de temps, je regarde de plus près, mais je pense pas avoir grand chose à dire de plus que les autres :). Je m'en était déja bien inspiré suite à tes précédentes publications :).
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
10 nov. 2008 à 11:04
Ricomat ->
Je t'ai envoyé la dernière version.
Elle est un peu plus complexe au niveau structure de données Midi.

Pour les All Notes OFF, je ne me suis pas penché dessus.

Peut tu me dire ce que tu penses de la structure des classes
Track(s)-> Tick(s)-> MidiEvent(s) ?

Merci d'avance pour ta coop

Afyn - Navedac
Ricomat Messages postés 3 Date d'inscription vendredi 7 mars 2003 Statut Membre Dernière intervention 10 novembre 2008
9 nov. 2008 à 16:59
Merci^^ mon adresse est eric.matras@free.fr
mon site http://www.rickforce.fr

J'ai ce matin remplacé dans mon appli les midiOutReset par :

Public Function StopMidiOut(Optional ByVal Canal As Integer = Nothing) As Integer
If Canal = Nothing Then
For i As Integer = 0 To 15
StopMidiMess(i)
Next
Else
StopMidiMess(Canal)
End If
End Function

Private Function StopMidiMess(ByVal Canal As Integer) As Integer
WMM.midiOutShortMsg(hMidiOut, ControlChange.All_Note_Canal_off Or Canal) '&7BB0
WMM.midiOutShortMsg(hMidiOut, ControlChange.Control_off Or Canal) '&H79B0
End Function

et ca marche sous vista pour ma part :).
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
8 nov. 2008 à 21:15
Ricomat j'ai une version un peu plus avancée si tu l'as veux ?

Pm moi une adresse maile je te l'envoie

Afyn - Navedac
NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
8 nov. 2008 à 18:27
Afyn>
Dsl, j'ai pas du voir passer le mail.
Donc, c'est enregistrer dans le xml qui porte le même nom de l'exécutable (ou la DLL).
Ricomat Messages postés 3 Date d'inscription vendredi 7 mars 2003 Statut Membre Dernière intervention 10 novembre 2008
8 nov. 2008 à 14:40
Avec Windows Vista,
Les midi not off ne sont pas envoyées lorsque l'on appui sur "stop" dans ton programme.
J'ai l'impression que MidiOutReset ne fonctionne pas sur Vista (ok sur XP). les nappes ne s'arrêtent pas.

Si tu as une solution, je suis preneur, j'ai le même problème dans une de mes appli^^.

++
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
4 août 2008 à 13:35
Bonjour :

-> NHenry je viens de comprendre ceci :
Pour indiquer par des commentaires à quoi servent tes méthodes, events, delegates, enum, ..., je te conseil d'utiliser les 3 ' , cela fera une infobulle, ce sera un peu mieux.

en fait les 3' correspondent au code xml ? par exemple

''' <summary>
''' MIDI Constant
''' </summary>
''' <remarks></remarks>

Effectivement ça fait une info bulle :) (C'est documenté ou ?)

-> Patrice : Oui j'ai pas ces options moi non plus ...

Afyn - Navedac
Le savoir faire des cancres
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
3 août 2008 à 09:21
#Begin Option Strict On/Off
#End Option Strict On/Off
n'existe pas : il ne s'agit que d'une suggestion d'un internaute.
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
10 juil. 2008 à 10:37
Ha oui ... je cherche à remplacer le Texte "Open" & "Start" dans la ToolBar par des icones vectorielles (pas de png gif ou autres donc) ... si quelqu'un à une idée sur
la façon de procéder ?

Merci
Afyn - Navedac
Le savoir faire des cancres
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
10 juil. 2008 à 10:37
> Concernant Infer, c'est revenir (à mon avis) à Strict Off.

Absolument pas du tout ! Le typage reste un typage fort, rien à voir avec du typage implicite : il suffit de laisser la souris sur la variable pour se convaincre de l'inférence de son type. Il ne s'agit pas d'un gadget pour les fainéants, mais d'une fonctionnalité requise pour l'implémentation de Linq.
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
10 juil. 2008 à 10:28
Bonjour les animateurs ...
Puisque tout le monde y va plein pot, je vous fait part, moi aussi, de mes idées.

Le plus dur pour un amateur comme moi, c'est la relecture du code que l'on a écrit.
Au bout d'un moment, on relit plus rien du tout !

C'est dur également de découper un code en parties facilement appréhendable par
d'autres.

Sur cette source, vous voyez le résultat pratiquement final de quelques années
de bricolage. Il y a presque autant de temps passé à débattre de la façon de
faire que de temps à écrire le programme.
Il faut avoir une vue d'ensemble de ce que l'on veut faire en même temps
qu'une vue des nombreux détails à régler.
Et rajoutez à cela le nombre de lignes de code que j'ai mis à la poubelle
après avoir décidé que ça n'apportait rien !

Donc voilà, je ne vous remercierai jamais assez de votre aide. Et EBArtSoft
a énormément pris de son temps pour me guider et donc lui je le remercie
encore plus particulièrement.

Le but recherché de cette source est de permettre de manipuler les données Midi.

Je crois que ce but est atteint.

J'avais aussi dans l'idée de donner un Kit " prêt à l'emploi ". Cet l'avis
des personnes qui réutiliserai ce travail qui pourrait être intéressant, dans
le sens des capacités du Kit et de ses limites.

Donc ... lachez du commentaire !

Je prend tout.

Merci encore

Afyn - Navedac
Le savoir faire des cancres
NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
10 juil. 2008 à 09:47
Merci EBArtSoft pour #begin, je ne connaissais pas (mais ne fonctionne que avec 2008, pas avec 2005).

Mais comme je manipule rarement des objets COM, Strict est toujours à On.
Concernant Infer, c'est revenir (à mon avis) à Strict Off.
Concernant le For Each, je viens d'apprendre un truc.
Pour IDisposable, cela ne coute rien de l'ajouter, mais ce n'est pas dans mon habitude; et d'ailleurs, ma remarque concernant la classe était juste, elle ne l'implémentait pas.

Merci pour cette mise au point.
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
10 juil. 2008 à 08:16
Moi j'aime bien titillier les pinailleurs, cela m'a permis d'apprendre que #Begin Option existe :-)
cs_EBArtSoft Messages postés 4525 Date d'inscription dimanche 29 septembre 2002 Statut Modérateur Dernière intervention 22 avril 2019 9
9 juil. 2008 à 22:56
Moi j'aime le beurre de cacahuete
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
9 juil. 2008 à 22:25
Moi je respecte beaucoup beaucoup beaucoup EBArtSoft !

Afyn - Navedac
cs_EBArtSoft Messages postés 4525 Date d'inscription dimanche 29 septembre 2002 Statut Modérateur Dernière intervention 22 avril 2019 9
9 juil. 2008 à 17:26
1) IDIsposable c'est une et une seule methode ("IDIsposable.Dispose") à implementer. Je ne vois la rien de bien mechant à ajouter aux objets deja presents.

2) Concernant l'"Option Strict On", il est reconnu de fait que l'activer sur la solution complete ne rend pas le code plus "securisé", plus "fiable" ou plus "aisé" surtout quand on manipule des objet COM. Autant l'employer partiellement lorsque cela est necessaire grace à

#Begin Option Strict On/Off
#End Option Strict On/Off

Sauf bien sur si on laisse les outils de validation faire le travail à sa place.

3) "For Each Item In Items" Utilise IEnumerable ce qui rend l'indexation plus lente qu'avec un simple "For I=1 To ItemsCount ... Items(I)"

4) Option Infer est du meme gout que strict il deresponsabilise le developpeur et ne fait pas toujours le bon choix par exemple :

dim a as double
a = 100
For I = 0 to A

I sera du type double hors ce n'est pas forcement ce que le developpeur veux. On en revient donc à la declaration explicite.

Concernant l'utilisation de plusieurs fichiers c'est un avis purement personnel. Je connais suffisamment Afyn pour lui exposer mes opinons même si elles ne sont pas "à la page" sans craindre quelconques jugements arbitraires.
cs_Patrice99 Messages postés 1221 Date d'inscription jeudi 23 août 2001 Statut Membre Dernière intervention 9 septembre 2018
9 juil. 2008 à 16:28
Rien que pour le plaisir de rajouter mon grain de sel, je dirai que EBArtSoft n'est plus à la page depuis plusieurs mois, car il suffit d'activer Option Infer à On pour laisser la seule ligne suivante, qui définira i en tant qu'Integer :
For i = 0 To 31
Et plusieurs classes par fichier .vb est parfois plus lisible que des milliers de fichiers qui trainent partout.
Afyn Messages postés 608 Date d'inscription samedi 3 août 2002 Statut Membre Dernière intervention 22 décembre 2016
9 juil. 2008 à 10:30
Merci pour vos commentaires.

Pour les commentaires, voilà en gros le fonctionnement :
Les datas Midi sont stockés dans une hiérachie d'objets.

Pour rappel, les données Midi peuvent avoir 2 ou 3 octets, D1, D2, (D3).
D1 est divisé en deux partie.
D1H correspond au type de message (NOTE_ON par exe)
D1L au canal Midi de 0 à 15
D1H et D1L peuvent être ignoré si leurs valeurs est identique
au message Midi précedent (running status)
D2 pour un msg NOTE_ON correspond au numéro de la note.
D3 pour un msg NOTE_ON correspond à la vélocité (force dela note)

Chaque MidiEvent est stocké dans une collection MidiEvents

Tick représente la position temporelle (absolue) de chaque MidiEvent
La collection Ticks est l'ensemble de tous les Tick ...
L'index de cette collection est la position temporelle en Tick

Track représente une piste et Tracks la collection

Tracks(0).Ticks(0).MidiEvents(0).msg représente le msg à envoyer.

Envoyer un msg prend 300µs. (je vous laisse calculer le débit !)

Dans le cas d'une lecture synchrone, on "Pulse" les msg à intervalle
régulier.
Le "Pulsage" est dans un thread différent de l'application. (délégate)
La durée de cet intervalle correspondra au Tempo du morceau.

L'avantage de tout ça ?
Cette façon de structurer les données permet de les modifier pendant
l'exécution du morceau, alors que sur beaucoup de séquenceur il
faut arrêter l'exécution pour pouvoir modifier une note.

La génération des NOTE_OFF est "à la volée"

EB m'a beaucoup aidé dans la conception de cette structure.
Elle est souple et performante. (Insérer 10 000 events prend 20 ms)
Il est possible que d'autre façon de faire existe, mais ce que
j'ai pu lire sur le NET était 100 fois plus compliqué.

Le lecteur de MidiFile n'est qu'un exemple d'utilisation de
cette structure hiérachique. Il est volontairement simple.
Le code dans MainForm n'est pas trés important puisque
beaucoup de choses sont dans la fichier MidiData.VB

Evidemment, il reste du boulot, mais le concept est solide.
NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
9 juil. 2008 à 09:45
EBArtSoft, désolé de te contredire, mais d'après mes connaissances :
- Using est réservé aux classes implémentant IDisposable, alors que (d'après ce que j'ai vu MidiEvents n'est pas dans ce cas).

Ensuite concernant :
If TimerID <> 0 Then
'Peut être remplacé par
If (TimerID) Then

C'est faux, il suffit de mettre Option Strict à On et le compilateur hurlera pour signaler qu'il ne peux pas caster implicitement un entier en un booléen.

Afyn>
Pour les perfs, évite CType quand tu as un héritage clair (pas d'adaptation Int -> Long par exemple) mais préfère DirectCast, c'est plus rapide.

# Dim Trk As New Track
#
# ' Efface le contenu des pistes
# For Each Trk In mCol.Values

# Next Trk

Tu peux définit uniquement :
Dim Trk As Track 'pas besoin du New à chaque fois.
Mais le mieux (comme le dit EbArtSoft) :
# For Each Trk as track In mCol.Values
# Next Trk

Pour indiquer par des commentaires à quoi servent tes méthodes, events, delegates, enum, ..., je te conseil d'utiliser les 3 ' , cela fera une infobulle, ce sera un peu mieux.

Voilà pour un premier jet.
cs_EBArtSoft Messages postés 4525 Date d'inscription dimanche 29 septembre 2002 Statut Modérateur Dernière intervention 22 avril 2019 9
8 juil. 2008 à 22:54
C'est pas mal du tout tu as fais d'enorme progres je trouve...

Si je peux me permettre quelques suggestions :

Plusieurs classes par fichier .vb
'Peut être remplacé par
Un fichier .vb par classe

Dim i As Integer
For i = 0 To 31
'peut être remplacé par :
For i As Integer = 0 To 31

If openFileDialog.ShowDialog() = True Then
'Peut être remplacé par :
If (openFileDialog.ShowDialog()) Then

If TimerID <> 0 Then
'Peut être remplacé par
If (TimerID) Then

Dim objNewMember As New MidiEvent
...
objNewMember = Nothing
'Peut être remplacé par :
Using objNewMember As New MidiEvent
...
End Using

et d'autres broutilles

Bravo

@+
Rejoignez-nous