1. Introduction.
2. Composition de la librairie MFAPI (Midi File API)
2.1. Fonction MFAPI de gestion de lecture MidiFile
2.1.1. Ouverture de fichier
2.1.2. Lecture de pistes consécutives :
2.1.3. Lecture d'une piste événement par événement
2.1.4. Fermeture de fichier
2.2. Fonction MFAPI de gestion d'écriture MidiFile :
2.2.1. Création / ouverture de fichier
2.2.2. Ecriture d'une séquence complète vers
une piste
2.2.3. Ecriture d'un piste événement par événement
2.2.4. Fermeture de fichier
3. Date des évènements
3.1. Date des évènements dans un fichier Midi
3.1.1. Représentation des unité de temps des dates
des événement MIDIFile
3.1.2. Unité: fraction de seconde
3.1.3. Unité: nombre d'impulsions par Noire (PPQN)
3.2. Date de l'évènement retourné par MidiFileReadEv
3.3. Date de l'évènement écrit par MidiFileWriteEv
4. Composition détaillée de la librairie MFAPI (Midi
File API)
4.1. Détails des fonctions MFAPI de lecture MidiFile
4.1.1. Ouverture fermeture de fichier
4.1.2. Lecture de pistes consécutives
4.1.3. Lecture d'un piste événement par événement
4.2. Détails des fonctions MFAPI de gestion d'écriture
MidiFile:
4.2.1. Création /Ouverture fermeture de fichier
4.2.2. Ecriture d'une séquence complète vers
une piste
4.2.3. Ecriture d'un piste événement par événement
4.3. Détails des fonctions internes de lecture d'événements
4.3.1. Procédures de lecture des méta événements
4.3.2. Détails des procédures de lecture des événements
Midi
4.4. Détails des fonctions internes d'écriture d'événements
4.4.1. Procédures d'écriture des méta événements
4.4.2. Procédures d'écriture des événements
Midi
1. Introduction.
Cette note permet de comprendre la composition et le comportement
des procédures des sources de la librairie Midifile. Ce
document est utile au développeur désirant utiliser
la librairie. Un descriptif détaillé de la composition
est également utile seulement aux développeurs désirant
faire évoluer la librairie.
2. Composition de la librairie MFAPI
(Midi File API) :
La librairie est composé d'un
jeu de procédures pour la gestion en lecture et d'un autre
jeu pour la gestion en écriture.
2.1. Fonction MFAPI de gestion de lecture MidiFile :
2.1.1. Ouverture de fichier :
Pour lire un fichier , le fichier doit exister
déjà. Il suffit de d'ouvrir à l'aide de MidiFileOpen
dans le mode MidiFileRead. Seules les opérations
de lecture sont possibles.
2.1.2. Lecture de pistes consécutives :
Après un appel à MidifileOpen,
(avec le mode MidifileAppend), il est possible de
lire entièrement une piste vers une séquence avec
MidiFileReadTrack qui retourne la séquence. La séquence
retournée est allouée par MidiFileReadTrack.
d'appelant doit exploiter et libérer la séquence
avec MidiFreeSeq.
Lorsque MidiFileReadTrack est utilisée, les évènements
de la piste du premier au dernier sont placés dans le même
ordre dans la séquence. Plusieurs pistes consécutives
peuvent être lues en utilisant plusieurs appels consécutifs
à MidiFileReadTrack.
2.1.3. Lecture d'une piste événement par
événement :
Alternativement pour lire les évènements
d'une piste un par un on peut utiliser les fonctions MidiFileChooseTrack,
MidiFileOpenTrack,MidiFileReadEv et MidiFileCloseTrack.
MidiFileChooseTrack positionne le pointeur de fichier au
début de la piste désigné.
MidFileOpenTrack ouvre la piste et doit être utilisé
après MidiFileChooseTrack ou après MidiFileCloseTrack.
MidiFileReadEv lit un événement dans la piste
courante. La piste doit être ouverte avec MidFileOpenTrack
avant la lecture du premier événement. Plusieurs
événements consécutifs peuvent être
lus en utilisant plusieurs appels consécutifs à
MidiFileReadEv.
Lorsque d'événement lu est le dernier de la piste,
un prochain appel à MidiFileReadEv ferme automatiquement
la piste courante. La macro IsTrackOpen permet de savoir
si la piste courante est toujours ouverte. Par conséquent
si une fin de piste été détecté grâce
à MidiFileReadEv, il n'est pas nécessaire
d'utiliser MidiFileCloseTrack.
MidiFileCloseTrack clôture la lecture de la piste courante
et initialise le pointeur de fichier au début de la piste
suivante. MidiFileCloseTrack est utile en cours de lecture
d'une piste pour pointer immédiatement sur la piste suivante.
2.1.4. Fermeture de fichier :
Pour clôturer d'enregistrement du fichier
MidiFileClose doit être utilisé.
2.2. Fonction MFAPI de gestion d'écriture
MidiFile :
2.2.1. Création / ouverture de fichier :
MidiFileCreate
doit être utilisé pour construire un nouveau fichier.
Si le fichier existe déjà il suffit de d'ouvrir
à d'aide de MidiFileOpen dans le mode MidiFileAppend.
Dans les 2 cas, seules les opérations d'écritures
sont possibles.
2.2.2. Ecriture d'une séquence complète
vers une piste:
Après un appel à MidiFileCreate
(ou MidifileOpen, dans le mode MidifileAppend),
il est possible d'écrire entièrement une séquence
sur une piste avec MidiFileWriteTrack qui écrit
une nouvelle piste à la fin du fichier.
Lorsque MidiFileWriteTrack est utilisée, les évènements
de la séquence du premier au dernier sont enregistrés
dans le même ordre sur la piste. Plusieurs pistes consécutives
peuvent être écrites en utilisant plusieurs appels
consécutifs à MidiFileWriteTrack.
2.2.3. Ecriture d'un piste événement par
événement :
Alternativement pour écrire une nouvelle
piste on peut utiliser les fonctions MidiFileNewTrack,MidiFileWriteEv
et MidiFileCloseTrack.
MidFileNewTrack crée un nouvel entête de piste
en fin de fichier et doit être utilisé après
MidiFileCloseTrack. MidiFileWriteEv écrit
un événement dans la piste courante. Plusieurs événements
consécutifs peuvent être écrit en utilisant
plusieurs appels consécutifs à MidiFileWriteEv.
MidiFileCloseTrack clôture d'écriture de la
piste courante.
2.2.4. Fermeture de fichier :
Pour clôturer d'enregistrement du fichier
MidiFileClose doit être utilisé.
3. Date des évènements
Le paragraphe suivant explique la datation
des évènements dans les fichiers standard MidiFile
et la datation utilisé par les fonctions de la librairie.
3.1. Date des évènements dans un
fichier Midi:
Dans un fichier Midi la date d'un événement est
représenté par une valeur relative à celle
de l'événement précédent.
La date du premier événement est relative à
0.
Exemple:
Soit une piste composé de 3 évènements suivants
avec leur date relative à l'événement précédent.
ev1: date relative: 10
ev2: date relative: 25
ev3: date relative: 5
L'événement ev1 doit être joué à
la date 10 relativement au début de piste.
L'événement ev2 doit être joué à
la date 10+25=35 relativement au début de piste.
L'événement ev3 doit être joué à
la date 35+5=40 relativement au début de piste.
3.1.1. Représentation des unité de temps
des dates des événement MIDIFile
L'unité de temps pour représenter la valeur relative
des dates est indiquée par le champ time situé
dans le descripteur MIDIFile (retourné par MidiFileOpen
ou MidiFileCreate). Le sandard MIDIFile adopte de 2 mode
de représentation de l'unité de temps. L'unité
de temps peut être exprimée en fraction de secondes
codés dans une représentation correspondant au système
SMPTE.
Ce mode est utile pour représenter une suite d'évènements
dans le système SMPTE tel que les évènements
Cue Point qui sont combinés avec des filmes vidéos.
L'unité de temps peut être exprimée en nombre
d'impulsions par Noire (PPQN). Ce mode de représentation
associé au méta événement de tempo
est adapté pour dater une suite d'évènements
musicaux.
3.1.2. Unité: fraction de seconde
La macro smpte(f) retourne true
lorsque time représente l'unité de temps en fraction
de seconde
La macro frame_par_sec(f) retourne le nombre de trames
par secondes, (Le nombre retourné est négatif).
La macro ticks_par_frame(f) retourne le nombre d'impulsions
par trame, f est le pointeur sur le descripteur MIDIFile. Sachant
que la date d'un événement est exprimé en
nombre d'impulsion par trame, le couple les macro frame_par_sec
et ticks_par_frame permette d'évaluer la date de l'événement
en fraction de seconde.
3.1.3. Unité: nombre d'impulsions par Noire (PPQN)
La macro smpte(f) retourne false lorsque time représente
l'unité de temps en nombre d'impulsion par Noire. La macro
ticks_par_quarterNote(f) retourne le nombre d'impulsion par Noire
(PPQN). f est le pointeur sur le descripteur MIDIFile.
3.2. Date de l'évènement retourné
par MidiFileReadEv:
La fonction MidiFileReadEv retourne un événement
avec sa date calculée ainsi:
La date est la somme de toutes les dates relatives aux
évènements précédents. Le résultat
est une date relative à 0. C'est la date par rapport
au début de la piste. C'est la date à laquelle l'événement
doit être joué.
Exemple:
Soit une piste composé de 3 évènements suivants
avec leur date relative à l'événement précédent.
ev1: date: 10 ev2: date: 25 ev3: date : 5
La lecture du 1er évènement ,ev1 retourne un événement
avec la date: 10
La lecture du 2éme évènement ,ev2 retourne
un événement avec la date: 35 (10+25)
La lecture du 1er évènement ,ev1 retourne un événement
avec la date: 40 (35+5)
L'unité de date est indiqué par la variable time
accessible par les macros décrites dans le paragraphe précédent.
Pour obtenir un événement il est nécessaire
de lire les événement précédents à
partir du début de la piste.
3.3. Date de l'évènement écrit
par MidiFileWriteEv:
La fonction MidiFileWriteEv écrit l'événement
sur le fichier avec une date relative à l'événement
précédemment écrit.
La fonction considère que la date porté
par l'événement à écrire est relative
à 0. Il s'agit d'une date supposée relative
au début de la piste.
La date de l'événement écrit (ev_ecrit)est
calculé ainsi en fonction de la date l'événement
à écrire (ev_a_ecrire) et de celle de l'événement
précédent à écrire:
(ev_prec_a_ecrire).
date (ev_ecrit) = date (ev_a_ecrire) - date (ev_prec_a_ecrire)
Exemple:
Soit une séquence composé des 3 évènements
suivants avec leur date relative au début de la piste.
ev1: date: 10 ev2: date: 35 ev3: date: 40
La date du 1er évènement écrit,ev1 est: 10
La date du 2ème évènement écrit,ev2
est: 25 (35 - 10)
La date du 3ème évènement écrit,ev3
est: 5 (40 - 35)
La fonction considère que l'unité de temps
de la date de l'événement à écrire
est celle indiqué par la variable time
accessible par les macros décrites dans
le paragraphe précédent. Si cela est nécessaire,
l'appelant doit normaliser la variable time et date de
l'événement à écrire avant l'appel
à MidiFileWriteEv.
4. Composition détaillée
de la librairie MFAPI (Midi File API) :
Le source de la librairie est composé des procédures
exportées et des procédures internes non exportées.
Les procédures exportées constituent d'interface
de programmation MFAPI (Midi File API). Les procédures
internes sont appelées par les procédures MFAPI.
Le paragraphe suivant décrit les procédures MFAPI
et les procédures internes appelées.
4.1. Détails des fonctions MFAPI de lecture
MidiFile :
4.1.1. Ouverture fermeture de fichier :
- Le pointeur de fichier MIDIFile est positionné sur
d'entête de la première piste à lire.
Procédures internes appelées:
- stdInit , init du descripteur MIDIFile
- mdf_getStdMode détermine le mode d'accès au fichier
- ReadMdfHeader , lecture de l'entête MThd du fichier.
- ErrOpen, erreur d'ouverture (dé-allocation).
lecture d'une piste vers une séquence.
Procédures MidiShare appelées:
- MidiNewSeq, allocation d'une séquence
Procédures MFAPI appelées:
- MidiFileOpenTrack , ouverture d'une piste
- MidiFileReadEv, lecture d'un évènement
Procédures MidiShare appelées:
- MidiFreeSeq , libération de la séquence interne.
4.1.3. Lecture d'un piste événement par événement :
Déplacement du pointeur de fichier.
Aucune fonction interne n'est appelée.
Ouverture d'une piste
Au retour s'il n'y à pas erreur :
L'entête de la piste à été luedans
le descripteur de fichier midiFile.
- _cnt = nombre d'octet de donnée dans la piste.
- curDate = 0
- opened = true
Le pointeur de fichier est positionné sur le 1er événement
à lire.
Procédures internes appelées:
- ReadTrkHeader, lit l'entête de piste à partir
du fichier
Lecture d'une événement (Midi
ou Méta événement).
Procédures internes appelées:
- mdf_GetDate, retourne la date de l'événement.
- ReadVarLen, lecture du valeur: Variable Length Quantity
- ReadEv , lecture d'un évènement
- mdf_read_meta , lecture d'un méta-événement.
- lecture d'un événement midi.
En lecture positionne le pointeur de fichier
sur l'entête de la piste suivante.
Au retour s'il n'y à pas erreur :
- Le descripteur MIDIFile est actualisé:
- opened = false
4.2. Détails des fonctions MFAPI de gestion
d'écriture MidiFile :
4.2.1. Création /Ouverture fermeture de
fichier :
- Le pointeur de fichier MIDIFile est positionné
sur d'entête de la première piste à lire.
Procédures internes appelées:
- stdInit , init du descripteur MIDIFile
- MidiNewSeq (ouverture en écriture )
- mdf_getStdMode détermine le mode d'accès au fichier
- ReadMdfHeader , lecture de l'entête MThd du fichier.
- ErrOpen, erreur d'ouverture (dé-allocation).
- MidiFreeSeq , libération de la séquence interne
(mode écriture).
- L'entête de piste "MTrk" est enregistré
sur le fichier.
- Le descripteur MIDIFile est initialisé:
Procédures MFAPI appelées:
- MidiFileCloseTrack , si une piste est couramment ouverte.
Procédures internes appelées:
- Create_trkHeader, création d'un entête de piste.
- Vidage de la séquence interne KeyOff.
- Mise à jour du champs 'longueur de piste' sur l'entête
de 'MTrk'.
- Mise à jour du champs 'nombre de piste' sur l'entête
'MThd'
Au retour s'il n'y à pas erreur :
-Actualise le descripteur MIDIFile:
- opened = false
Procédures internes appelées:
-FlushKeyOff, vidage de la séquence interne keyOff.
4.3. Détails des fonctions internes de lecture
d'événements :
Les 2 familles d'événements sont :
Les évènements Midi : Note on, Note off etc.
Les méta événements : Tempo, Key signature,
Lyric etc
C'est la procédure interne ReadEv qui permet la lecture
d'un événement Midi ou d'un meta événement.La
lecture d'un méta événement est effectué
par un appel à la mdf_read_meta. La lecture d'un événement
midi est directement effectué par ReadEv. A chaque événement
Midi ou méta événement correspond une procédure
de lecture dont le rôle est d'allouer un événement
(MidiNewEv) à partir des données de l'événement
de la piste.
4.3.1. Procédures de lecture des méta
événements:
Les paramètres en entrée et en sortie sont les mêmes
pour toutes les procédures.
Les paramètres en entrées sont:
- Le pointeur sur le descripteur MIDIFile.
- Le nombre d'octet de données à lire.
Les paramètres en sortie sont:
- l'adresse de l'événement alloué.
- nil, dans les cas suivant:
- L' événement lu a été ignoré.
- Erreur d'allocation événement (MidiFile_errno=MidiFileErrEvs).
Au retour l'appelant doit tester le compte rendu qui doit être
un des cas suivant:
1) Les erreurs:
- erreurs d'allocation évènement.
- erreur de lecture fichier .
2) L'événement est ignoré.
3) Lecture réussi.
Tableau des types de meta événement et des procédures
internes utilisées:
MIDI file 1.0 | MidiShare | |||
Name meta events | Code | Id type MidiSare | code type | procédures |
Sequence Number | 0 | typeSeqNum | 134 | read_seqNum |
Text | 1 | typeText | 135 | read_text |
Copyright | 2 | typeCopyright | 136 | read_text |
Sequence/Track Name | 3 | typeSeqName | 137 | read_text |
Instrument Name | 4 | typeInstrName | 138 | read_text |
Lyric | 5 | typeLyric | 139 | read_text |
Marker | 6 | typeMarker | 140 | read_text |
Cue Point | 7 | typeCuePoint | 141 | read_text |
MIDI Channel | 32(20H) | typeChanPrefix | 142 | read_chanPref |
MIDI port | 33(21H) | Ignored | mdf_ignoreEv | |
End of Track | 47(2FH) | typeEndTrack | 143 | read_endTrack |
Tempo | 81(51H) | typeTempo | 144 | read_tempo |
SMPTE Offset | 84(54H) | typeSMPTEOffset | 145 | read_smpte |
Time Signature | 88(58H) | typeTimeSign | 146 | read_timeSign |
Key Signature | 89(59H) | typeKeySign | 147 | read_KeySign |
Proprietary Event | 127(7FH) | typeSpécific | 148 | read_text |
MIDI file 1.0 | MidiShare | |||
Canal oriented events | ||||
Name MIDI events | status | Id type MidiSare | code type | procédures |
Key On | 80H | typeKeyOff | 2 | read_2DataEv |
Key Off | 90h | typeKeyOn | 1 | read_2DataEv |
Poly Key Pressure | A0H | typeKeyPress | 3 | read_2DataEv |
Control Change | B0H | typeCtrlChange | 4 | read_2DataEv |
Program Change | C0H | typeProgChange | 5 | read_1DataEv |
Channel Pressure | D0H | typeChanPress | 6 | read_1DataEv |
Pith Bend Change | E0H | typePitchWheel | 7 | read_2DataEv |
Non canal oriented events | ||||
System Exclusive | F0H | typeSysEx | 17 | read_sysex |
MTC quarter frame | F1H | typeQuarterFrame | 130 | read_1DataEv |
Song Position Pointer | F2H | typeSongPos | 8 | read_2DataEv |
Song Select | F3H | typeSongSel | 9 | read_1DataEv |
Undefined | F4H | ignored | read_undef | |
Undefined | F5H | ignored | read_undef | |
Tune Request | F6H | typeTune | 14 | read_0DataEv |
Data Stream | F7H | typeStream | 18 | read_sysex |
Timing Midi Clock | F8H | typeClock | 10 | read_0DataEv |
Undefined | F9H | ignored | read_undef | |
Start | FAH | typeStart | 11 | read_0DataEv |
Continue | FBH | typeContinue | 12 | read_0DataEv |
Stop | FCH | typeStop | 13 | read_0DataEv |
FDH | ignored | read_undef | ||
Active Sensing | FEH | typeActiveSens | 15 | read_0DataEv |
System Reset | FFH | typeReset | 16 | read_undef |
MIDI file 1.0 | MidiShare | |||
Name meta events | Code | Id type MidiSare | code type | procédures |
Sequence Number | 0 | typeSeqNum | 134 | write_seqNum |
Text | 1 | typeText | 135 | write_text |
Copyright | 2 | typeCopyright | 136 | write_text |
Sequence/Track Name | 3 | typeSeqName | 137 | write_text |
Instrument Name | 4 | typeInstrName | 138 | write_text |
Lyric | 5 | typeLyric | 139 | write_text |
Marker | 6 | typeMarker | 140 | write_text |
Cue Point | 7 | typeCuePoint | 141 | write_text |
MIDI Channel | 32 (20H) | typeChanPrefix | 142 | write_chanPref |
MIDI port | 33 (21H) | Ignored | ||
End of Track | 47 (2FH) | typeEndTrack | 143 | write_endTrack |
Tempo | 81 (51H) | typeTempo | 144 | write_tempo |
SMPTE Offset | 84 (54H) | typeSMPTEOffset | 145 | write_smpte |
Time Signature | 88 (58H) | typeTimeSign | 146 | write_timeSign |
Key Signature | 89 (59H) | typeKeySign | 147 | write_KeySign |
Proprietary Event | 127 (7FH) | typeSpécific | 148 | write_text |
MIDI file 1.0 | MidiShare | |||
Canal oriented events | ||||
Name MIDI events | status | Id type MidiSare | code type | procédures |
voir note 1 | 90H | typeNote | 0 | write_note |
Key On | 90H | typeKeyOn | 1 | write_2DataEv |
Key Off | 80h | typeKeyOff | 2 | write_2DataEv |
Poly Key Pressure | A0H | typeKeyPress | 3 | write_2DataEv |
Control Change | B0H | typeCtrlChange | 4 | write_2DataEv |
Program Change | C0H | typeProgChange | 5 | write_1DataEv |
Channel Pressure | D0H | typeChanPress | 6 | write_1DataEv |
Pith Bend Change | E0H | typePitchWheel | 7 | write_2DataEv |
Non canal oriented events | ||||
Song Position Pointer | F2H | typeSongPos | 8 | write_2DataEv |
Song Select | F3H | typeSongSel | 9 | write_1DataEv |
Timing Midi Clock | F8H | typeClock | 10 | write_0DataEv |
Start | FAH | typeStart | 11 | write_0DataEv |
Continue | FBH | typeContinue | 12 | write_0DataEv |
Stop | FCH | typeStop | 13 | write_0DataEv |
Active Sensing | FEH | typeActiveSens | 15 | write_0DataEv |
System Reset | FFH | typeReset | 16 | dont_write |
System Exclusive | F0H | typeSysEx | 17 | write_sysex |
Tune Request | F6H | typeTune | 14 | write_0DataEv |
Data Stream | F7H | typeStream | 18 | write_sysex |
MTC quarter frame | F1H | typeQuarterFrame | 130 | write_1DataEv |
voir note 2 | B0H | typeCtrl14b | 131 | write_Ctrl14b |
voir note 3 | B0H | typeNonRegParam | 132 | write_NRegP |
voir note 4 | B0H | typeRegParam | 133 | write_RegP |