Télécharger le script ! - mod phpBB
// Figure 22.10 : DemoMidi.java
// Simuler un clavier de piano permettant de jouer plusieurs instruments
// ainsi que des caractéristiques d'enregistrement, de lecture de séquences
// et de simulation de l'action d'un piano mécanique lors de la lecture MIDI.
// Packages de noyau Java.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
// Packages d'extension Java.
import javax.swing.*;
import javax.swing.event.*;
import javax.sound.midi.*;
public class DemoMidi extends JFrame {
// Enregistrement de données MIDI.
private EnregistreurMidi enregistreurMidi;
// Accès aux fonctions MIDI de synthétiseur.
private SynthetiseurMidi synthetiseurMidi;
// Données des fichiers MIDI.
private DonneesMidi donneesMidi;
// Minuterie pour la simulation des données MIDI au piano.
private Timer minuteriePiano;
// Touches du clavier de piano.
private JButton boutonNote[];
// Glissières pour le volume sonore et le tempo.
private JSlider boutonVolume, boutonTempo;
// Conteneurs et panneaux pour mettre la GUI en place.
private Container conteneur;
private JPanel panneauControle, panneauBoutons;
// GUI incluant le sélecteur d'instrument et les boutons.
private JComboBox selecteurInstrument;
private JButton boutonReecouter, boutonEnregistrer,
boutonSauvegarder, boutonPiano, boutonOuvrirMidi;
// Tempo, dernière note de piano invoquée et volume MIDI.
private int tempo, derniereNoteOn = -1, volumeMidi = 40;
// Valeur boolean indiquant si le programme est en mode d'enregistrement.
private boolean modeEnregistrement = false;
// 1er numéro de note MIDI de la 1ere touche, quantité maximale de touches.
private static int PREMIERE_NOTE = 32, QTE_MAX_TOUCHES = 64;
// Constructeur de DemoMidi.
public DemoMidi()
{
super( "Programme de démonstration MIDI" );
conteneur = getContentPane();
conteneur.setLayout( new BorderLayout() );
// Le synthétiseur doit être instancié pour permettre la synthèse.
synthetiseurMidi = new SynthetiseurMidi();
// Créer les touches de piano.
creerTouches();
// Ajouter le panneau de contenu dans le cadre.
panneauControle = new JPanel( new BorderLayout() );
conteneur.add( panneauControle, BorderLayout.NORTH );
creerCommandesConfig();
// Ajouter le panneau de boutons dans le cadre.
panneauBoutons = new JPanel( new GridLayout( 5, 1 ) );
panneauControle.add( panneauBoutons, BorderLayout.EAST );
// Créer la GUI.
creerBoutonsReecouterSauvegarder();
creerBoutonEnregistrer();
creerBoutonPianoMecanique();
} // fin du constructeur
// Méthode utilitaire pour créer les touches de piano.
private void creerTouches()
{
// Panneau contenant les touches.
JPanel panneauTouches = new JPanel( null );
conteneur.add( panneauTouches, BorderLayout.CENTER );
// Touches du clavier de piano.
boutonNote = new JButton[ QTE_MAX_TOUCHES ];
// Définir les boutons des notes selon la QTE_MAX_TOUCHES et leur hauteur.
for ( int i = 0; i < QTE_MAX_TOUCHES; i++ ) {
final int note = i;
boutonNote[ i ] = new JButton();
// Définir des touches blanches.
boutonNote[ i ].setBackground( Color.white );
// Définir un espacement adéquat pour les boutons.
boutonNote[ i ].setBounds( ( i * 11 ), 1, 11, 40 );
panneauTouches.add( boutonNote[ i ] );
// Inscrire un écouteur de souris pour les événements de souris.
boutonNote[ i ].addMouseListener(
// Classe interne anonyme de gestion des événements de souris.
new MouseAdapter() {
// Invoquer la note de la touche quand la souris survole la touche.
public void mouseEntered( MouseEvent mouseEvent )
{
// Si en mode d'enregistrement, envoie un message au récepteur.
if ( modeEnregistrement )
synthetiseurMidi.sendMessage(
ShortMessage.NOTE_ON,
note + PREMIERE_NOTE, volumeMidi );
// Sinon, ne jouer que la note.
else
synthetiseurMidi.midiNoteOn(
note + PREMIERE_NOTE, volumeMidi );
// Changer la touche blanche en touche bleue.
boutonNote[ note ].setBackground(
Color.blue );
}
// Message qui désactive la note quand la souris quitte la touche.
public void mouseExited( MouseEvent mouseEvent )
{
if ( modeEnregistrement )
synthetiseurMidi.sendMessage(
ShortMessage.NOTE_OFF,
note + PREMIERE_NOTE, volumeMidi );
else
synthetiseurMidi.midiNoteOff(
note + PREMIERE_NOTE );
boutonNote[ note ].setBackground(
Color.white );
}
} // fin du MouseAdapter
); // fin de l'appel à addMouseListener
} // fin de la boucle for
} // fin de la méthode creerTouches
// Définir les commandes de configuration.
private void creerCommandesConfig()
{
JPanel panneauConfig =
new JPanel( new GridLayout( 5, 1 ) );
panneauControle.add( panneauConfig, BorderLayout.WEST );
selecteurInstrument = new JComboBox(
synthetiseurMidi.getInstruments() );
panneauConfig.add( selecteurInstrument );
// Inscrire un ActionListener pour les événements selecteurInstrument.
selecteurInstrument.addActionListener(
// Classe interne anonyme de gestion des événements selecteurInstrument.
new ActionListener() {
// Changer l'instrument courant.
public void actionPerformed( ActionEvent e )
{
// Changer l'instrument du synthétiseur.
synthetiseurMidi.changeInstrument(
selecteurInstrument.getSelectedIndex() );
}
} // fin d'ActionListener
); // fin de l'appel à la méthode addActionListener
JLabel etiquetteVolume = new JLabel( "Volume" );
panneauConfig.add( etiquetteVolume );
boutonVolume = new JSlider(
SwingConstants.HORIZONTAL, 5, 80, 30 );
// Inscrire un ChangeListener pour les variations du curseur de volume.
boutonVolume.addChangeListener(
// Classe interne anonyme de gestion des événements du curseur de volume.
new ChangeListener() {
// Changer le volume MIDI.
public void stateChanged( ChangeEvent changeEvent )
{
volumeMidi = boutonVolume.getValue();
}
} // fin de la classe ChangeListener
); // fin de l'appel à la méthode addChangeListener
panneauConfig.add( boutonVolume );
JLabel etiquetteTempo = new JLabel( "Tempo" );
panneauConfig.add( etiquetteTempo );
boutonTempo = new JSlider(
SwingConstants.HORIZONTAL, 1, 10, 1 );
// Inscrire un ChangeListener pour les variations du curseur de tempo.
boutonTempo.addChangeListener(
// Classe interne anonyme de gestion des événements du curseur de tempo.
new ChangeListener() {
// Changer le tempo MIDI si la valeur est changée.
public void stateChanged( ChangeEvent changeEvent )
{
tempo = boutonTempo.getValue();
}
} // fin du ChangeListener
); // fin de l'appel à la méthode addChangeListener
boutonTempo.setEnabled( false );
panneauConfig.add( boutonTempo );
} // fin de la méthode creerCommandesConfig
// Définir les boutons de réécoute et de sauvegarde.
private void creerBoutonsReecouterSauvegarder()
{
boutonReecouter = new JButton( "Réécouter" );
// Inscrire un ActionListener pour les événements boutonReecouter.
boutonReecouter.addActionListener(
// Classe interne anonyme de gestion des événements boutonReecouter.
new ActionListener() {
// Jouer la dernière séquence MIDI enregistrée.
public void actionPerformed( ActionEvent e )
{
if ( enregistreurMidi != null )
enregistreurMidi.lecture();
}
} // fin de l'ActionListener
); // fin de l'appel à la méthode addActionListener
panneauBoutons.add( boutonReecouter );
boutonReecouter.setEnabled( false );
boutonOuvrirMidi = new JButton( "Ouvrir fichier MIDI" );
// Inscrire un ActionListener pour les événements boutonOuvrirMidi.
boutonOuvrirMidi.addActionListener(
// Classe interne anonyme de gestion des événements boutonOuvrirMidi.
new ActionListener() {
// Lire le fichier MIDI.
public void actionPerformed( ActionEvent e )
{
File fichierMidi = getFichier();
if ( fichierMidi == null )
return;
donneesMidi = new DonneesMidi();
// Préparer la piste MIDI.
if ( donneesMidi.initialiser( fichierMidi ) == false )
return;
// Jouer les données MIDI.
donneesMidi.lecture();
}
} // fin de l'ActionListener
); // fin de l'appel à la méthode addActionListener
panneauBoutons.add( boutonOuvrirMidi );
boutonSauvegarder = new JButton( "Sauvegarder MIDI" );
// Inscrire un ActionListener pour les événements boutonSauvegarder.
boutonSauvegarder.addActionListener(
// Classe interne anonyme de gestion des événements boutonSauvegarder.
new ActionListener() {
// Obtenir le fichier requis et sauvegarder les données MIDI.
public void actionPerformed( ActionEvent e )
{
File fichierSauvegarde = getFichierSauvegarde();
if ( fichierSauvegarde != null )
enregistreurMidi.sauvegarderSequence( fichierSauvegarde );
}
} // fin de l'ActionListener
); // fin de l'appel à la méthode addActionListener
panneauBoutons.add( boutonSauvegarder );
boutonSauvegarder.setEnabled( false );
} // fin de la méthode creerBoutonsReecouterSauvegarder
// Créer le bouton d'enregistrement.
private void creerBoutonEnregistrer()
{
boutonEnregistrer = new JButton( "Enregistrer" );
// Inscrire un ActionListener pour les événements boutonEnregistrer.
boutonEnregistrer.addActionListener(
// Classe interne anonyme de gestion des événements boutonEnregistrer.
new ActionListener() {
// Démarrer ou arrêter l'enregistrement.
public void actionPerformed( ActionEvent e )
{
// Enregistrer les données MIDI si le bouton est "Enregistrer".
if ( boutonEnregistrer.getText().equals("Enregistrer") ) {
if ( enregistreurMidi == null ) {
// Créer une nouvelle instance d'enregistreur en
// passant via le transmetteur du synthétiseur.
enregistreurMidi = new EnregistreurMidi(
synthetiseurMidi.getTransmitter() );
if ( enregistreurMidi.initialiser() == false )
return;
}
else
enregistreurMidi.makeTrack();
enregistreurMidi.startRecord();
// Désactiver la réécoute durant l'enregistrement.
boutonReecouter.setEnabled( false );
// Changer le bouton Enregistrer en bouton Arrêter.
boutonEnregistrer.setText( "Arrêter" );
modeEnregistrement = true;
} // fin du if
// Arrêter l'enregistrement si le bouton est "Arrêter".
else {
enregistreurMidi.stopRecord();
boutonEnregistrer.setText( "Enregistrer" );
modeEnregistrement = false;
boutonReecouter.setEnabled( true );
boutonSauvegarder.setEnabled( true );
}
} // fin de la méthode actionPerformed
} // fin de l'ActionListener
); // fin de l'appel à la méthode addActionListener
panneauBoutons.add( boutonEnregistrer );
} // fin de la méthode creerBoutonEnregistrer
// Créer le bouton et les fonctionnalités du piano mécanique.
private void creerBoutonPianoMecanique()
{
boutonPiano = new JButton( "Piano mécanique" );
// Inscrire un ActionListener pour les événements de boutonPiano.
boutonPiano.addActionListener(
// Classe interne anonyme de gestion des événements boutonPiano.
new ActionListener() {
// Initialiser les données MIDI et la minuterie pour le piano.
public void actionPerformed( ActionEvent e )
{
File fichierMidi = getFichier();
if ( fichierMidi == null )
return;
donneesMidi = new DonneesMidi();
// Préparer la piste MIDI.
if ( donneesMidi.initialiser( fichierMidi ) == false )
return;
if ( donneesMidi.initialiserPiste() == false )
return;
// Définir le tempo initial de la séquence MIDI.
tempo = donneesMidi.getResolution();
// Nouvelle instance de la minuterie pour la gestion des notes
// du piano et le déclenchement des touches suivant le tempo.
minuteriePiano = new Timer(
donneesMidi.getDelai() * tempo,
new GestionnaireMinuterie() );
boutonOuvrirMidi.setEnabled( false );
boutonPiano.setEnabled( false );
boutonTempo.setEnabled( true );
minuteriePiano.start();
} // fin de la méthode actionPerformed
} // fin de l'ActionListener
); // fin de l'appel à la méthode addActionListener
panneauBoutons.add( boutonPiano );
} // fin de la méthode creerBoutonPianoMecanique
// Classe interne de gestion des événements MIDI chronométrés.
private class GestionnaireMinuterie implements ActionListener {
// Simuler action de touche pour la note s'il existe un événement, passer
// à l'événement suivant de la piste et définir le prochain intervalle
// de la méthode de minuterie invoquée à l'atteinte du nouvel événement.
public void actionPerformed( ActionEvent actionEvent )
{
// Si la dernière touche valide est à "ON", la recolorer en blanc.
if ( derniereNoteOn != -1 )
boutonNote[ derniereNoteOn ].setBackground(
Color.white );
noteAction();
donneesMidi.allerEvenementSuivant();
// Stopper le piano mécanique à la fin de la piste MIDI.
if ( donneesMidi.isFinDePiste() == true ) {
if ( derniereNoteOn != -1 )
boutonNote[ derniereNoteOn ].setBackground(
Color.white );
minuteriePiano.stop();
boutonOuvrirMidi.setEnabled( true );
boutonPiano.setEnabled( true );
boutonTempo.setEnabled( false );
return;
} // fin du if de isFinDePiste
// Définir l'intervalle avant le prochain événement musical.
minuteriePiano.setDelay(
donneesMidi.getDelai() * tempo );
} // fin de la méthode actionPerformed
} // fin de la classe interne GestionnaireMinuterie
// Déterminer quelle note est jouée
// conformément au message MIDI reçu.
private void noteAction()
{
// Pour un message NOTE_ON, jouer la note et enfoncer la touche du piano.
if ( donneesMidi.getCommandeEvenement() ==
ShortMessage.NOTE_ON ) {
// S'assurer que la note valide est comprise dans le clavier du piano.
if ( ( donneesMidi.getNote() >= PREMIERE_NOTE ) &&
( donneesMidi.getNote() < PREMIERE_NOTE + QTE_MAX_TOUCHES ) ) {
derniereNoteOn = donneesMidi.getNote() - PREMIERE_NOTE;
// Colorer la touche en rouge.
boutonNote[ derniereNoteOn ].setBackground( Color.red );
// Transmettre et joue la note via le synthétiseur.
synthetiseurMidi.sendMessage( 144,
donneesMidi.getNote(), donneesMidi.getVolume() );
} // fin du if
// Sinon, aucune dernière touche actionnée.
else
derniereNoteOn = -1;
} // fin du if
// Pour un message NOTE_OFF, termine la note MIDI
// et recolore la touche correspondante en blanc.
else
// Si la commande du message est NOTE_OFF.
if ( donneesMidi.getCommandeEvenement() ==
ShortMessage.NOTE_OFF ) {
if ( ( donneesMidi.getNote() >= PREMIERE_NOTE ) &&
( donneesMidi.getNote() < PREMIERE_NOTE + QTE_MAX_TOUCHES ) ) {
// Recolorer la touche correspondante en blanc.
boutonNote[ donneesMidi.getNote() -
PREMIERE_NOTE ].setBackground( Color.white );
// Envoyer un message NOTE_OFF au récepteur.
synthetiseurMidi.sendMessage( 128,
donneesMidi.getNote(), donneesMidi.getVolume() );
}
} // fin du if
} // fin de la méthode noteAction
// Obtenir le fichier de sauvegarde de l'ordinateur.
public File getFichierSauvegarde()
{
JFileChooser choixFichier = new JFileChooser();
choixFichier.setFileSelectionMode(
JFileChooser.FILES_ONLY );
int resultat = choixFichier.showSaveDialog( this );
if ( resultat == JFileChooser.CANCEL_OPTION )
return null;
else
return choixFichier.getSelectedFile();
}
// Obtenir le fichier de l'ordinateur.
public File getFichier()
{
JFileChooser choixFichier = new JFileChooser();
choixFichier.setFileSelectionMode(
JFileChooser.FILES_ONLY );
int resultat = choixFichier.showOpenDialog( this );
if ( resultat == JFileChooser.CANCEL_OPTION )
return null;
else
return choixFichier.getSelectedFile();
}
// Exécuter l'application.
public static void main( String args[] )
{
DemoMidi midiTest = new DemoMidi();
midiTest.setSize( 711, 225 );
midiTest.setDefaultCloseOperation ( EXIT_ON_CLOSE );
midiTest.setVisible( true );
}
} // fin de la classe DemoMidi
/******************************************************************************
* (C) Copyright 2002 par Deitel & Associates, Inc. et Prentice Hall *
* Tous droits réservés. *
* *
* RENONCIATION: Les auteurs et l'éditeur de cet ouvrage ont fait tous *
* les efforts pour préparer ce livre et les programmes qu'il contient, *
* y compris dans l'élaboration, la recherche et les contrôles sur l'effica- *
* cité des théories et programmes. Les auteurs et l'éditeur n'offrent *
* aucune garantie de quelque ordre que ce soit, expresse ou implicite, *
* pour ce qui concerne ces programmes ni la documentation présentés *
* dans ce livre. L'auteur et l'éditeur ne pourront être tenus pour *
* responsables de tout dommage accessoire ou indirect, lié à ou causé *
* par la fourniture, la performance ou l'utilisation de ces programmes. *
*****************************************************************************/