DédéAmp arrive… TREMBLE VINCENT BOLLORE ! – part 1

Les vacances approchant et éprouvant le besoin de créer un truc parfaitement inutile mais représentant tout de même un challenge, c’est grâce (ou à cause) de l’ami @gootsy que je me suis lancé dans l’écriture d’un player de MP3 en… Powershell ! Après tout, j’avais bien fait un sampler cet été, alors pourquoi ne pas pousser l’enveloppe (comme on dit en aéronautique) ? Suivez-moi dans l’aventure…

Fear the Dédé

Pour ceux qui n’ont pas compris la référence dans le titre, un peu d’histoire : un de players le plus connus et utilisés au monde, bien avant l’avènement du génial VLC, a été WinAmp, dont la première version remonte à 1997, il y a presque vingt ans ! Sans nul doute, il aura été un des moteurs de la révolution du MP3, avant même Napster, en popularisant ce format de musique compressée. Son éditeur, Nullsoft, a été racheté en 1999 pour une somme rondelette par AOL, le FAI leader de l’époque, avant d’être cédé en 2014 à une société belge, Radionomy, elle-même rachetée depuis lors par Vivendi en 2015… Et comme chacun sait, Vivendi appartient au groupe Bolloré, et ce n’est ni plus moins qu’au terrible Vincent Bolloré himself que je m’attaque donc frontalement (mais surtout modestement !) !

Oh oui, tu as raison d’être soucieux, Vince… It’s time to kick ass and chew bubblegum, et j’en ai plus en stock.

Blague à part, parlons un peu technique. En soi, faire un simple player de MP3 en Powershell n’a rien de sorcier, mais dès qu’on commence à vouloir quelques fonctionnalités, ça se complique rapidement. Comme pour le sampler, il suffit de faire appel à ce que .NET nous offre, en l’occurrence un objet Windows Media Player, qui lui n’est pas limité à jouer des wav, et va nous permettre de nous exploser les tympans à grands coups de mp3.

Pour avoir étudié ce format (dérivé du MPEG, son nom officiel étant d’ailleurs MPEG-1 (et 2) Audio-Layer III), il n’est pas franchement simple à décoder, mais heureusement d’autres que moi s’en sont chargés, inutile de réinventer la roue. De même, si les tags ID3v1 (qui ne sont pas natifs dans le MP3 mais sont des blocs de données rajoutés) contenant le nom de l’artiste, le titre de la chanson et l’album, etc, sont relativement simples à relire (j’avais fait un éditeur de tags sur Atari ST et ce sans doc, c’est dire si c’était facile), ce n’est pas le cas à partir des tags ID3v2, qui contiennent évidemment plus de métadonnées, mais dans un format totalement différent… Cela dit, là aussi d’autres se sont chargés du boulot, et ont même fait une librairie rien que pour ça : pourquoi ne pas s’en servir ? Et ça permet d’apprendre à charger et à utiliser une DLL, alors n’hésitons pas.

Enfin, même si Powershell est avant tout un langage destiné à l’automatisation de tâches (un langage de script, quoi), on peut faire tellement de choses avec (j’en découvre encore tous les jours, et DédéAmp en est un exemple), pourquoi se limiter à un truc pourrave en mode console ? Autant lui adjoindre une jolie interface graphique (enfin jolie… les goûts et les couleurs, hein…) : pour cela, nous allons comme pour le sampler utiliser un bon vieux windows.form (parce que WPF je n’accroche pas, c’est comme ça, c’est la vie).

Au fur et à mesure de l’écriture du code – plus j’ajoutais de fonctionnalités -, j’ai du aussi utiliser d’autres possibilités de Powershell, comme la gestion des événements, les objets, et j’en passe. Nous découvrirons tout ceci dans cette série d’articles, où je vous expliquerai comment arriver à tel résultat, pourquoi telle fonction, ce que fait tel bout de code, etc.

Bon c’est pas WinAmp mais ça pète pas mal quand même !

A l’heure où j’écris ces lignes (nous sommes le samedi 17 décembre et il est 6h38… oui je me lève tôt, la grasse mat je ne sais pas ce que c’est…), DédéAmp est loin d’être fini mais il est déjà fonctionnel (et ce n’est que la v0.02), et a de la gueule ! Il manque encore quelques fonctionnalités que je garde en réserve pour plus tard (soit parce que je n’ai pas encore commencé à réfléchir à comment je devais m’y prendre, soit parce que je n’ai pas encore trouvé la solution pour que ça marche…). Et puis si vous avez des idées, n’hésitez pas, DédéAmp peut devenir collaboratif !

Ce qu’il nous faut

  • D’abord, un PC sous Windows (7 ou supérieur), n’importe quelle édition fera l’affaire. La capture d’écran ci-dessus a été faite sous Windows 10.
  • Powershell (qui est installé par défaut), et tant qu’à faire Powershell ISE qui est quand même bien pratique. Si vous avez Powershell Studio de Sapien Technologies, c’est encore mieux, mais comme c’est payant… Si vous n’êtes pas sous Windows 10, pensez à récupérer Powershell v5.0, vous le trouverez en téléchargeant WMF 5.0 (Windows Management Framework). La version 5.1 est sortie avec Windows Server 2016 et est présente dans les builds Insider de Windows 10, mais je ne l’ai pas encore vu en package pour des versions plus anciennes de Windows. On peut donc rester sur la 5.0 pour l’instant, même si évidemment DédéAmp devrait fonctionner avec la 5.1. Notez que même si désormais Powershell existe pour Mac et Linux, DédéAmp risque de ne pas fonctionner (car tout n’est pas implémenté sous ces OS d’une part, et parce qu’il faudra la version adaptée de…)
  • …la librairie taglib-sharp, qui va nous permettre de lire les tags ID3 (elle ne fait pas que ça, mais nous nous contenterons de lire les ID3). Vous la trouverez ici : https://download.banshee.fm/taglib-sharp/ . Prenez la dernière version, à l’heure actuelle, il s’agit de la 2.1 (il faut donc aller dans le répertoire 2.1.0.0 et récupérer taglib-sharp-2.1.0.0-windows.zip. Je la mettrai dans l’archive de DédéAmp, mais prenez l’habitude de pas faire confiance aux DLL qui viennent d’on ne sait où : allez toujours les récupérer sur le site officiel, on ne sait pas dans quelle mesure elle a été modifiée et ce qu’elle contient… c’est si simple de coller un malware dans une DLL à l’air innocent…
  • Quelques images pour les boutons, le fond du formulaire, et l’icône : je les fournirai dans l’archive aussi, mais rien ne vous empêche d’en mettre d’autre.
  • Le script ImageToBase64.ps1 (qui n’est pas de moi mais de Wayne Lindimore) pour convertir les images en base64 afin de les intégrer directement dans le script : je le fournirai aussi dans l’archive, pas d’inquiétude.
  • Des MP3… c’est quand même mieux pour tester… Par défaut, DédéAmp ira voir dans le répertoire Musique de votre profil Windows (autrement dit, dans le répertoire C:\Users\votrelogin\Music), mais évidemment on pourra aller les chercher ailleurs (les miens sont sur un NAS).

Ensuite, créez-vous un répertoire où vous mettrez dedeamp.ps1, taglib-sharp.dll (dans l’archive zip, elle est dans \taglib-sharp-2.1.0.0-windows\Libraries, inutile de prendre l’autre dll qui s’y trouve), les images, etc. Il faudra ensuite débloquer la dll (en gros, autoriser son exécution, car Windows vous en empêchera sous prétexte qu’elle vient d’Internet, une source peu fiable… on ne peut guère le lui reprocher, ma foi). Pour cela, c’est très simple, il suffit de faire un clic droit sur la DLL, d’aller dans les Propriétés, et de cocher la case Débloquer (ou son équivalent, le nom peut changer) :

Ça m’arrive de débloquer, mais là c’est juste une DLL…

Si vous ne le faites pas, Powershell ne pourra pas charger et donc exécuter la librairie, ça fera de méchantes erreurs et DédéAmp va planter misérablement, voire formater votre disque dur et cramer votre processeur… Non je plaisante, mais bref, débloquez-la, ça ne coûte rien et la vie sera plus belle.

Lancez ensuite Powershell ISE (via le menu Démarrer, sinon faites une simple recherche), pas besoin d’être Administrateur pour ça, sauf si c’est la première fois que vous lancez ISE, car vous devrez autoriser l’exécution de scripts en tapant la commande :

Set-ExecutionPolicy Unrestricted

Voilà, nous sommes prêts à entrer dans le vif du sujet.

Le vif du sujet

(et là, Vincent Bolloré s’attend au pire. Il a raison.)

J’ai organisé le script en plusieurs sections qui sont refermables sous ISE. Ces sections sont délimitées par des commentaires un peu particuliers (j’en avais parlé dans l’article du sampler), à savoir #region et #endregion. Ainsi il y a une section variables (où j’initialise certaines de mes variables, ça alors), une section fonctions, une section formulaire, etc. Je décortiquerai le code section par section, pas forcément dans le bon ordre, afin de me focaliser sur un point précis. Si jamais je manquais de clarté dans mes explications, n’hésitez pas à poser des questions en commentaires…

Commençons par le tout début du script, et notamment notre section (ou région) Variables…

# DédéAmp Player
# Par Dédé Lateur - 13-17/12/2016
# https://dede.laserforce.org

#region Variables
$version="0.02"
$MusicFolder = "$env:USERPROFILE\Music"
$global:i=0
$global:status=0 # 0: idle, 1: playing, 2: paused
$statusarray=@("En attente","Lecture","En pause")
$path=Split-Path -Parent $PSCommandPath
$help={    
    Switch ($this.name) 
    {
        "play"  {$tip = "Lecture/Pause"}
        "stop" {$tip = "Stop"}
        "next" {$tip = "Piste suivante"}
        "prev" {$tip = "Piste précédente"}
        "mute" {$tip = "Couper/Rallumer le son"}
        "browse" {$tip = "Sélectionner le dossier"}
        "info" {$tip = "A propos de DédéAmp Player v$version"}
    }
    $tooltip.SetToolTip($this,$tip)
} 
#endregion
  • La variable $version contient… le numéro de version de DédéAmp… Évidemment, ça devrait évoluer dans le temps !
  • La variable $MusicFolder contient le chemin par défaut vers nos MP3. J’utilise dedans la variable d’environnement $env:USERPROFILE qui pointe vers le répertoire de mon profil (C:\users\dédé), et j’ajoute derrière le répertoire \Music (sur une version française de Windows, il s’agit du pseudo-répertoire Musique, mais sur le disque, le répertoire est bien \Music)
  • La variable $global:i servira à nous positionner dans la playlist (j’y reviendrai plus tard). Pourquoi $global ? Parce qu’il s’agit d’une variable globale, dont le scope – l’étendue – s’étendra à tout le script. On peut en effet avoir des variables locales, qui n’existent que dans une fonction… et donc ne sont pas utilisables en dehors de cette fonction. J’avoue ne pas avoir essayé de l’appeler simplement $i, peut-être que ça aurait marché (cette variable est en effet utilisée à plusieurs endroits du script, hors et dans des fonctions), je n’ai pas voulu prendre le risque et en ai fait une variable globale.
  • Idem pour la variable $global:status, qui servira à indiquer l’état du player : en attente, en cours de lecture et en pause.
  • Le tableau $statusarray contient ces mêmes états mais sous forme de texte afin de l’afficher dans le formulaire. Ainsi, si je passe le player en pause, je n’ai qu’à dire que la boîte Etat du formulaire contient $statusarray[2], et hop, j’ai le bon message. Évidemment, j’en reparlerai plus tard.
  • La variable $path contient le chemin où se trouve le script dedeamp.ps1. Je m’en servirai pour charger taglib-sharp.dll (on ne peut hélas pas la charger en l’intégrant comme les images, sauf à faire une bidouille bien moche qui consiste à réécrire la dll à chaque fois sur le disque, et à la supprimer une fois le script quitté. Bof. Autant l’avoir dans le même répertoire que le script, comme ça si une nouvelle version sort (j’en doute, mais bon), vous pourrez copier la dernière version dans le répertoire sans vous prendre la tête à l’intégrer dans le script).
  • Enfin, la variable $help va nous servir à afficher des tooltips, autrement dit un petit message apparaissant lorsque la souris reste (hover, comme dans hoverboard, Marty) au-dessus d’un de nos boutons :

Le tooltip qui apparaît lorsque la souris est au-dessus du bouton Play

Dans le formulaire, comme vous le verrez, j’ai nommé mes boutons (ils ont une propriété name. Celle-ci est définie comme ceci (dans la région formulaire)) :

$button_play.Name="play"
$button_play.add_MouseHover($help)

De même, le bouton stop a sa propriété name qui est égale à “stop”, etc. Vous pouvez voir ensuite que je lui colle le gestionnaire d’évènement “MouseHover”, en précisant la variable $help… Celle-ci est particulière car elle ne contient pas une valeur, mais un bloc de code ! Notez bien les accolades { et } qui délimitent ce bloc de code… Donc en fonction de la propriété name de l’objet (le bouton) au-dessus duquel passe la souris, je donnerai une valeur particulière (un message) à la variable $tip, que je passerai à l’objet $tooltip, qui n’est pas encore créé à ce stade, mais plus loin dans le script, dans la région Formulaire :

$tooltip = New-Object System.Windows.Forms.ToolTip

Cet objet se débrouillera pour afficher le tooltip (c’est sa raison d’être dans la vie, il a été créé pour ça, et il fait partie de la classe System.Windows.Form).

Un petit rappel sur la programmation orientée objet, avec une belle métaphore automobile comme il se doit (c’est d’ailleurs marrant qu’on fasse autant de comparaison entre les bagnoles et les ordinateurs, un jour je saurai pourquoi, mais j’avoue que je l’ignore. Reste que ça fait trente ans que je fais aussi ces comparaisons) :

  • Il y a des objets de la vie réelle qu’on appelle des voitures, et font donc partie de la classe voiture
  • Ces voitures ne sont pas toutes pareilles, ces objets voitures ont donc des propriétés différentes : la marque, le modèle, la motorisation, la couleur…
  • Ces voitures peuvent faire des choses : avancer, reculer, tourner à gauche, tourner à droite… on parlera de méthode.

Ainsi, en pseudo-code (que je viens d’inventer pour l’occasion… occasion, voitures… haha, tu l’as, tu l’as ?) :

classe Voiture

$voiture1 = Nouvelle Voiture
{
       # ici je définis ses propriétés
       marque : "Opel"
       modèle : "Zafira"
       couleur : "gris silver"
}

$voiture2 = Nouvelle Voiture
{
       marque : "Renault"
       modèle : "Twingo"
       couleur : "Caca d'oie"
}

# Appliquons la méthode Avancer() à notre $voiture1 :
$voiture1.Avancer() 
# oh miracle, elle avance !

# Et si je veux savoir la couleur de notre $voiture2 ?
Print $voiture2.couleur

# Le résultat est :
Caca d'oie

Tiens, un Opel Zafira gris silver… ne serait-ce pas notre $voiture1 ? Et bah oui !

Vous verrez que DédéAmp utilise tout un tas d’objets (ne serait-ce que pour le formulaire, qui est lui-même un objet de la classe System.Windows.Form, donc ayant des propriétés et auquel on peut appliquer des méthodes, et lui-même possédant des objets enfants, comme les boutons, les textboxes etc..), y compris un objet créé de toutes pièces (autrement dit, un objet “custom”, rien à voir avec le tuning, ça va bien les comparaisons avec l’automobile, y’a des limites à tout !), que nous verrons dans la suite de cette série d’articles !

D’ici là, portez-vous bien et tchüss !

 

 

 

1 commentaire

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.