home *** CD-ROM | disk | FTP | other *** search
/ Computer Music Interactif…cial Edition 1999 Winter / cd 3.iso / mac / Mac / Shares / Midishare™1.68 / Development Tools / Sources Examples / msEcho / msEcho.p < prev    next >
Encoding:
Text File  |  1992-03-07  |  34.8 KB  |  946 lines  |  [TEXT/MPS ]

  1. {••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  2. {•                                  ECHO                                        •}
  3. {•------------------------------------------------------------------------------•} 
  4. {•                                                                                 •}
  5. {• Le programme ECHO présenté ici, fait partie d'une série d'exemples à         •}
  6. {• caractère pédagogique (enfin j'espère !) sur la façon d'utiliser MIDISHARE.    •}
  7. {•                                                                                 •}
  8. {• Comme son nom l'indique, ECHO effectue un écho temps-réel sur les notes        •}
  9. {• reçues. Il dispose de quatre types de controles :                            •}
  10. {•       - Le delai entre les échos successifs (en millisecondes)               •}
  11. {•       - La variation de vélocité entre les échos successifs.                    •}
  12. {•       - La variation de hauteur entre les échos successifs.                    •}
  13. {•       - Le choix du canal Midi de réception.                                    •}
  14. {•                                                                                •}
  15. {•------------------------------------------------------------------------------•}
  16. {•        © GRAME 1989, Yann Orlarey et Hervé Lequay                                •}
  17. {••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••}
  18.  
  19.  
  20. Program Echo;
  21.  
  22. USES    Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf, Traps, MIDIShareUnit;
  23.  
  24.  
  25. const    AppleID    = 128;    AppleMenu    = 1;
  26.         FileID    = 129;    FileMenu    = 2;
  27.         EditID    = 130;    EditMenu    = 3;
  28.             UndoI    = 1;    CutI    = 3;    CopyI    = 4;    PasteI    = 5;    ClearI    = 6;
  29.         
  30.     WindowID    = 128;                     { ID fenêtre de l'application        }
  31.     AboutID        = 129;
  32.     AlertID        = 500;
  33.         
  34.     resumeMask    = $01;                    { suspend/resume mask                }
  35.         
  36.  
  37.     DelaySB     = 1;                    { Item ScrollBar du delai            }
  38.     VelSB         = 2;                    { Item ScrollBar de la vélocité        }
  39.     PitchSB     = 3;                    { Item ScrollBar de la hauteur        }
  40.     ChanSB         = 4;                    { Item ScrollBar du canal Midi        }    
  41.  
  42.     DelayTXT     = 5;                    { Item Affichage du delai            }
  43.     VelTXT         = 6;                    { Item Affichage de la vélocité        }
  44.     PitchTXT     = 7;                    { Item Affichage de la hauteur        }
  45.     ChanTXT        = 8;                    { Item Affichage du canal Midi        }    
  46.  
  47.  
  48. type
  49.     TCtrlInfoPtr = ^TCtrlInfo;
  50.     TCtrlInfo    = record                { Info necessaires pour les ScrollBar    }
  51.             val:    integer;                { valeur courante                    }
  52.             mode:    integer;                { 0: horizontal, 1: vertical        }
  53.             Disp:    integer;                { numéro de l'item à mettre à jour    }
  54.             DVal:    integer;                { ambitus des valeur                }
  55.             DPos:     integer;                { ambitus des positions                }
  56.             oldVal:    integer;                { valeur au début du Track            }
  57.             oldPos:    integer;                { position au début du Track        }
  58.         end;
  59. var    
  60.     myRefNum:                integer;                            { numéro d'appl. Midi                }
  61.     myFilter:                 TFilter;                            { filtre pour les événements Midi    }
  62.  
  63.     myWindow:                 windowPtr;                            { fenêtre                            }
  64.  
  65.     doneFlag:                boolean;                            { flag d'arrêt                        }
  66.     
  67.     gMac:                    SysEnvRec;                            { machine…                            }
  68.     eventPending:            boolean;                            { vrai si événement en attente        }
  69.     hasWNE:                    boolean;                            { vrai si WaitNextEvent implémenté    }
  70.     foreGround:                boolean;                            { vrai si en foreGround                }
  71.  
  72.     myEvent:                eventRecord;                        { pour la main event loop            }
  73.     theChar:                char;                                { pour la gestion des touches        }
  74.     dragRect:                rect;                                { rect de déplacement de fenêtre    }
  75.     myMenus:                array[AppleMenu..EditMenu] of MenuHandle;
  76.                                                                 { les menus                            }
  77.     whichItem:                integer;                            { item sélectionné                    }
  78.     whichCtrl:                ControlHandle;                        { Control sélectionné                }
  79.     whichInfo:                TCtrlInfoPtr;                        { infos relatives au Ctrl select.    }
  80.     
  81.     theDelay,
  82.     theVel,
  83.     thePitch,
  84.     theChan:                TCtrlInfo;                            { info relatives aux ScrollBar        }    
  85.     
  86.     theDuration:            integer;                            { durée par défaut des notes        }
  87.  
  88.  
  89.  
  90. (********************************************************************************)
  91. (*                                 UTILITAIRES                                        *)
  92. (*------------------------------------------------------------------------------*)
  93. (*                                                                                 *)
  94. (********************************************************************************)
  95.  
  96. {$S Initialize}
  97. Function TRAPAVAILABLE (tNumber: integer; tType: trapType): boolean;
  98. (*    Vérification de l'implémentation d'une trappe                                *)
  99. begin
  100.     TrapAvailable:= NGetTrapAddress(tNumber,tType) <> GetTrapAddress(_Unimplemented)
  101. end;
  102.  
  103. {$S Main}
  104. Function ISAPPWINDOW (aWind: windowPtr): boolean;
  105. (* vérifie si la fenêtre appartient à l'application                                *)
  106. begin
  107.     if aWind = nil then
  108.         IsAppWindow:= false
  109.     else 
  110.         IsAppWindow:= windowPeek(aWind)^.windowKind >= 0
  111. end;
  112.  
  113. {$S Main}
  114. Function ISDAWINDOW (aWind: windowPtr): boolean;
  115. (* vérifie si la fenêtre appartient à un accessoire de bureau                    *)
  116. begin
  117.     if aWind = nil then
  118.         IsDAWindow:= false
  119.     else 
  120.         IsDAWindow:= windowPeek(aWind)^.windowKind < 0
  121. end;
  122.  
  123. {$S Main}
  124. Procedure CenterRectOnScreen (var aRect: Rect);
  125. { aRect rectangle global à centrer sur écran (dragRect)                    }
  126. var    screenSize    : Point;
  127.     rectSize    : Point;
  128. begin
  129.     with dragRect do
  130.         SetPt(screenSize,right - left,bottom - top);
  131.     with aRect do begin
  132.         SetPt(rectSize,right - left,bottom - top);
  133.         left:= dragRect.left + (screenSize.h - rectSize.h) div 2;
  134.         top:= dragRect.top + (screenSize.v - rectSize.v) div 5;
  135.         topLeft:= point(PinRect(dragRect,topLeft));
  136.         right:= left + rectSize.h;
  137.         bottom:= top + rectSize.v;
  138.         end;
  139. end;
  140.  
  141. {$S Main}
  142. Function GetNewCenteredDialog (dialogID: integer): DialogPtr;
  143. var    dlogTemplate    : DialogTHndl;
  144. begin
  145.     GetNewCenteredDialog := nil;
  146.     dlogTemplate := DialogTHndl(GetResource('DLOG', dialogID));
  147.     if dlogTemplate <> nil then begin
  148.         CenterRectOnScreen(dlogTemplate^^.boundsRect);
  149.         GetNewCenteredDialog:= GetNewDialog(dialogID, nil, pointer(-1));
  150.         end
  151.     else SysBeep(2)                                                { At least give some indication }
  152. end;
  153.  
  154. {$S Main}
  155. Procedure AlertUser (alertID: integer);
  156. var    alrtTemplate    : AlertTHndl;
  157.     temp            : integer;
  158. begin
  159.     alrtTemplate := AlertTHndl(GetResource('ALRT', alertID));
  160.     if alrtTemplate <> nil then begin
  161.         SetCursor(arrow);
  162.         CenterRectOnScreen(alrtTemplate^^.boundsRect);
  163.         temp:= Alert(alertID,nil)
  164.         end
  165.     else SysBeep(2)                                             { At least give some indication        }
  166. end;
  167.  
  168.  
  169. (********************************************************************************)
  170. (*                                 SET UP MENUS                                    *)
  171. (*------------------------------------------------------------------------------*)
  172. (* Installation de la barre de menus                                              *)
  173. (*                                                                                 *)
  174. (* Les paramètres de l'appel :                                                    *)
  175. (* ---------------------------                                                    *)
  176. (*                                                                                 *)
  177. (*        aucun                                                                    *)
  178. (*                                                                                 *)
  179. (********************************************************************************)
  180.  
  181. {$S Initialize}
  182. Procedure SETUPMENUS;
  183. var    i:    integer;
  184. begin    
  185.     myMenus[AppleMenu] := GetMenu(AppleID);                        { menu Pomme                        }
  186.     AddResMenu(myMenus[AppleMenu],'DRVR');                        { ajout des accessoires de bureau    }
  187.     myMenus[FileMenu] := GetMenu(FileID);                        { menu Fichier                        }
  188.     myMenus[EditMenu] := GetMenu(EditID);                        { menu Edit                            }
  189.     for i := AppleMenu to EditMenu do
  190.         InsertMenu(myMenus[i], 0);
  191.     DrawMenuBar                                                    { affiche la barre des menus        }
  192. end;
  193.             
  194.  
  195. (********************************************************************************)
  196. (*                                 MIN et MAX                                        *)
  197. (*------------------------------------------------------------------------------*)
  198. (* Calcul du Minimum et du Maximun de deux entiers.                                  *)
  199. (*                                                                                 *)
  200. (* Les paramètres de l'appel :                                                    *)
  201. (* ---------------------------                                                    *)
  202. (*                                                                                 *)
  203. (*        n1    :    entier                                                            *)
  204. (*        n2    :    entier                                                            *)
  205. (*                                                                                 *)
  206. (********************************************************************************)
  207.  
  208. {$S Main}
  209. Function Max (n1,n2: integer): integer;
  210. begin
  211.     if n1<n2 then Max := n2 else Max := n1
  212. end;
  213.  
  214. Function Min (n1,n2: integer): integer;
  215. begin
  216.     if n1>n2 then Min := n2 else Min := n1
  217. end;
  218.  
  219.  
  220. (********************************************************************************)
  221. (*                                 SET DIA TEXT                                    *)
  222. (*------------------------------------------------------------------------------*)
  223. (* Routine pour changer le texte d'un item de dialogue.                            *)
  224. (*                                                                                 *)
  225. (* Les paramètres de l'appel :                                                    *)
  226. (* ---------------------------                                                    *)
  227. (*                                                                                 *)
  228. (*        d    :    pointeur sur un dialogue.                                        *)
  229. (*        i    :    numéro de l'item dont on veut changer le texte.                    *)
  230. (*        s    :    chaine de caractères à placer.                                    *)
  231. (*                                                                                 *)
  232. (********************************************************************************)
  233.  
  234. {$S Main}
  235. procedure setDiaText (d: dialogPtr; i: integer; s: str255);
  236.     var t: integer;
  237.         h: handle;
  238.         r: rect;
  239.     begin
  240.         getDItem(d,i,t,h,r);
  241.         if t < statText then 
  242.             setCTitle(controlHandle(h),s)
  243.         else {if t < iconItem then}
  244.             setIText(h,s);
  245.     end;
  246.  
  247.  
  248. (********************************************************************************)
  249. (*                                 SET DIA NUM                                        *)
  250. (*------------------------------------------------------------------------------*)
  251. (* Routine pour changer le texte d'un item de dialogue.                            *)
  252. (*                                                                                 *)
  253. (* Les paramètres de l'appel :                                                    *)
  254. (* ---------------------------                                                    *)
  255. (*                                                                                 *)
  256. (*        d    :    pointeur sur un dialogue.                                        *)
  257. (*        i    :    numéro de l'item dont on veut changer le texte.                    *)
  258. (*        n    :    valeur numérique à afficher.                                    *)
  259. (*                                                                                 *)
  260. (********************************************************************************)
  261.  
  262. {$S Main}
  263. procedure setDiaNum (d: dialogPtr; i: integer; n: longint);
  264.     var t: integer;
  265.         h: handle;
  266.         r: rect;
  267.         s: str255;
  268.     begin
  269.         numToString(n,s);
  270.         setDiaText(d,i,s);
  271.     end;
  272.  
  273.  
  274. (********************************************************************************)
  275. (*                                 ECHO NOTE                                        *)
  276. (*------------------------------------------------------------------------------*)
  277. (* La procedure de calcul de l'écho. Elle est appelée sous interruptions à         *)
  278. (* chaque réception d'une note. Ensuite, elle se rappelle récursivement         *)
  279. (* pour calculer les échos suivants, par le biais d'un MidiCall qui réalise un     *)
  280. (* appel différé dans le temps.                                                    *)
  281. (*                                                                                 *)
  282. (* Le principe de cette procédure d'écho est faire circuler une note            *)
  283. (* dont la hauteur et la vélocité varient à chaque écho jusqu'a ce que l'un des    *)
  284. (* deux paramètres sorte des bornes 0 à 127. De plus, à chaque écho, une copie     *)
  285. (* de cette note est envoyée.                                                    *)
  286. (*                                                                                 *)
  287. (* Les paramètres d'un appel par le biais d'un MidiCall sont imposés, et sont     *)
  288. (* au nombre de cinq : la date de l'appel (longint), le numéro de référence de     *)
  289. (* l'application (integer), et trois paramètres dont l'usage est libre sous        *)
  290. (* réserve qu'ils soient de la taille d'un longint ou d'un pointeur.            *)
  291. (*                                                                                 *)
  292. (* Les paramètres de l'appel :                                                    *)
  293. (* ---------------------------                                                    *)
  294. (*                                                                                 *)
  295. (*         d:        date de l'appel (longint, en ms)                                *)
  296. (*         myRefNum:    numéro de référence unique de l'application (integer)        *)
  297. (*         e:        pointeur sur la note dont il faut calculer l'écho                *)
  298. (*        a2,a3:    paramètres obligatoires, mais non utilisés ici.                    *)
  299. (*                                                                                 *)
  300. (********************************************************************************)
  301.  
  302. {$S Main}
  303. procedure echoNote(d: longint; myRefNum: integer; e: midiEvPtr; a2,a3: longint);
  304. var    c:        midiEvPtr;
  305.     v,p:    integer;
  306. begin
  307.     c := midiCopyEv(e);                                            { crée une copie de la note        }
  308.     if c <> Nil then midiSendAt(myRefNum, c, d);                { si la copie a réussi, l'emet    }
  309.     v := e^.vel+theVel.val;                                        { calc. la nouvelle vélocité    }
  310.     p := e^.pitch+thePitch.val;                                    { calc. la nouvelle hauteur        }
  311.     if (v>0) and (v<128) and (p>=0) and (p<128) then begin        { si dans les limites 0..127    }
  312.         e^.vel := v; e^.pitch := p;                                { met à jour la note            }
  313.         midiCall (@echoNote, d+theDelay.val, myRefNum, longint(e), 0, 0) { et se rappel à la date voulue}
  314.     end else
  315.         midiFreeEv(e)                                            { sinon, detruit la note et fin    }
  316. end;
  317.         
  318.         
  319.  
  320. (********************************************************************************)
  321. (*                             TREAT MIDI EVENTS                                    *)
  322. (*------------------------------------------------------------------------------*)
  323. (* La procedure de réception des événements Midi. Elle est appelée automatique-    *)
  324. (* ment par MidiShare, sous    interruptions, chaque fois que l'application        *) 
  325. (* reçoit de nouveaux événements.                                                 *)
  326. (*                                                                                 *)
  327. (* Pour ce faire, l'adresse de cette routine à été fournie à MidiShare à         *)
  328. (* l'ouverture de l'application par un MidiSetRcvAlarm.                            *)
  329. (*                                                                                 *)
  330. (* Cette procédure doit obligatoirement comporter un paramètre, qui est le         *)
  331. (* numéro de référence unique de l'application (integer).                        *)
  332. (*                                                                                 *)
  333. (* Le principe de cette procédure est d'aller récupérer les événements reçus,    *)
  334. (* de vérifier qu'ils sont du bon canal et d'appeler s'il y a lieu la procédure *)
  335. (* d'écho par le biais d'un MidiCall différé dans le temps.                        *)
  336. (*                                                                                 *)
  337. (* Les paramètres de l'appel :                                                    *)
  338. (* ---------------------------                                                    *)
  339. (*                                                                                 *)
  340. (*        myRefNum:    numéro de référence Midi de l'application.                        *)
  341. (*                                                                                 *)
  342. (********************************************************************************)
  343.  
  344. {$S Main}
  345. procedure treatMidiEvents(myRefNum: integer);
  346. var    e:        MidiEvPtr;
  347.     d,n:     longint;
  348. begin
  349.     n := midiCountEvs(myRefNum);                                    { compte les événements reçus        }
  350.     d := midiGetTime+theDelay.val;                                { calc. la date du prochain echo    }
  351.     while n > 0 do begin                                        { tant qu'il reste des Ev à traiter    }
  352.         e := midiGetEv(myRefNum);                                    { en prendre un et :                    }
  353.         if (theChan.val<>0) and (theChan.val <> e^.chan + 1) then    { vérifier son canal            }
  354.             midiFreeEv(e)                                        { s'il n'est pas bon, le détruire    }
  355.         else if e^.evType = typeNote then                         { si c'est une note,                 }
  356.             midiCall (@echoNote, d, myRefNum, longint(e), 0, 0)    {  appeler la proc. EchoNote         }
  357.         else if e^.vel>0 then begin                                { si c'est un KeyOn de vel>0        }
  358.             e^.evType     := typeNote;                            {  le transformer en une note        }
  359.             e^.dur        := theDuration;                            {  définir une durée par defaut        }
  360.             midiCall (@echoNote, d, myRefNum, longint(e), 0, 0)    {  appeler la proc. EchoNote        }
  361.            end
  362.         else midiFreeEv(e);                                        { sinon le détruire                    }
  363.         n := n-1;
  364.     end
  365. end;
  366.  
  367.  
  368. (********************************************************************************)
  369. (*                             SET UP FILTERS                                        *)
  370. (*------------------------------------------------------------------------------*)
  371. (* Cette procédure définit les valeurs du filtre de l'application. Un filtre     *)
  372. (* est composé de trois parties, qui sont trois tableaux de booléens :            *) 
  373. (*                                                                                 *)
  374. (*        un tableau de 256 bits pour les ports Midi acceptés                        *)
  375. (*        un tableau de 256 bits pour les types d'événements acceptés                *)
  376. (*        un tableau de  16 bits pour les canaux Midi acceptés                    *)
  377. (*                                                                                 *)
  378. (* Les bits sont positionnés à True pour accepter et à False pour refuser.         *)
  379. (*                                                                                 *)
  380. (* Les paramètres de l'appel :                                                    *)
  381. (* ---------------------------                                                    *)
  382. (*                                                                                 *)
  383. (*        aFilter:    un filtre MidiShare.                                        *)
  384. (*                                                                                 *)
  385. (********************************************************************************)
  386.  
  387. {$S Initialize}
  388. procedure setUpFilters(var aFilter: TFilter);
  389. var i:    integer;
  390. begin
  391.     for i := 0 to 255 do begin                    { à priori on refuse tout        }
  392.         myFilter.port[i] := false;
  393.         myFilter.evType[i] := false;
  394.     end;
  395.                                                 { mais on accepte                }
  396.     myFilter.port[modemPort]     := true;        { les événements en provenance    }
  397.     myFilter.port[printerPort]     := true;        { des ports Modem et Printer    }
  398.     
  399.     myFilter.evType[typeNote]     := true;        { les événements de type Note    }
  400.     myFilter.evType[typeKeyOn]     := true;        { et de type Key On                }
  401.     
  402.     for i := 0 to 15 do begin                    { sur les 16 canaux Midi         }
  403.         myFilter.channel[i] := true;
  404.     end;
  405.                                                 { enfin,                        }
  406.     midisetFilter(myRefNum,@aFilter)                { on passe le filtre à MidiShare}
  407. end;
  408.     
  409.     
  410. (********************************************************************************)
  411. (*                                 SET UP MIDI                                        *)
  412. (*------------------------------------------------------------------------------*)
  413. (* Cette procédure définit les différents paramètres necessaires au fonction-    *)
  414. (* nement Midi de l'application. Tout d'abord, le MidiOpen de l'application        *)
  415. (* qui lui permet de se signaler à MidiShare, et d'obtenir un numèro de réfé-    *)
  416. (* rence unique pour la suite des opérations. La chaine de caractères passée en    *)
  417. (* argument sert au catalogue des applications ouvertes que maintient MidiShare.*)
  418. (* Ensuite la définition de l'alarme de réception, une procédure appelée auto-    *)
  419. (* matiquement par MidiShare, à chaque fois que l'application va recevoir de    *)
  420. (* nouveaux événements. Troisièmement, la définition des filtres de réceptions    *)
  421. (* qui permettent à l'application de spécifier à MidiShare les événements         *)
  422. (* qu'elle désire recevoir. Enfin l'établissement des connections qui vont         *)
  423. (* relier l'entrée et la sortie de l'application aux ports Midi externes.        *)
  424. (*                                                                                 *)
  425. (* Les paramètres de l'appel :                                                    *)
  426. (* ---------------------------                                                    *)
  427. (*                                                                                 *)
  428. (*        aucun paramètre.                                                        *)
  429. (*                                                                                 *)
  430. (********************************************************************************)
  431.  
  432. {$S Initialize}
  433. procedure SetUpMidi;
  434. var    name:        str255;
  435.     apRefNum:    integer;
  436.     apParam:    Handle;
  437.     aRefNum:    integer;
  438.  
  439.     Procedure FAILSETUP (strIndex: integer);
  440.     var    msgStr:    str255;
  441.     begin
  442.         GetIndString (msgStr,AlertID,strIndex);                { message d'alerte suivant erreur    }
  443.         ParamText(name,msgStr,'','');
  444.         AlertUser(AlertID);
  445.         ExitToShell                                                { et quitte                            }
  446.     end;
  447.     
  448. begin
  449.     GetAppParms(name,apRefNum,apParam);                    { récupérer le nom d'application    }
  450.     if not MidiShare then
  451.         FailSetUp(1);                                    { MidiShare n'est pas installé        }
  452.         
  453.     myRefNum:= MidiOpen(name);                            { ouverture en Midi                    }
  454.     if myRefNum = MidiErrSpace then
  455.         FailSetUp(2);                                    { impossible, plus de place            }
  456.     
  457.     midiSetRcvAlarm(myRefNum, @treatMidiEvents);        { définit la procédure de réception    }
  458.     setUpFilters(myFilter);                                { programmation des filtres            }
  459.     midiConnect(0,myRefNum,true);                        { connecte l'appl. aux entrées Midi    }
  460.     midiConnect(myRefNum,0,true);                        { connecte l'appl. aux sorties Midi }
  461. end;
  462.  
  463.  
  464. (********************************************************************************)
  465. (*                                 SET UP SCROLL BAR                                *)
  466. (*------------------------------------------------------------------------------*)
  467. (* Cette procédure crée l'enrobage necessaire au suivi des scrollBar.            *)
  468. (* afficheurs.                                                                    *)
  469. (*                                                                                 *)
  470. (* Les paramètres de l'appel :                                                    *)
  471. (* ---------------------------                                                    *)
  472. (*                                                                                 *)
  473. (*        d        :    pointeur vers le dialogue concerné.                            *)
  474. (*        info    :    pointeur vers info necessaires au suivi du ScrollBar.        *)
  475. (*        me        :    numéro d'item du ScrollBar.                                    *)
  476. (*        disp    :    numéro d'item du texte d'affichage de la valeur du ScrollB.    *)
  477. (*        dir        :    direction du ScrollBar: 0 = horiz., 1 = vert.                *)
  478. (*                                                                                 *)
  479. (********************************************************************************)
  480.  
  481. {$S Main}
  482. procedure SetUpScrollBar(d: dialogPtr; info: TCtrlInfoPtr; me, disp: integer; dir: integer);
  483. var    h:        controlHandle;
  484.     t,v:    integer;
  485.     r:        rect;
  486. begin
  487.     getDItem(d,me,t,handle(h),r);                    { récupère le SB d'aprés son num. d'item}
  488.     setCRefCon(h, longint(info));                    { lui attache les info pour le suivi.    }
  489.     info^.val  := getCtlValue(h);                     { récupère la valeur courante du SB.    }
  490.     setDiaNum(d,disp,info^.val);                    { l'affiche une première fois.            }
  491.     info^.mode := dir;                                { définit la dir. du SB (Horiz. ou Vert.)}
  492.     info^.disp := disp;                                { définit l'item servant à l'affichage.    }
  493.     info^.DVal := GetCtlMax(h)-GetCtlMin(h);        { définit l'ambitus des valeurs.        }
  494.     if dir=0 then                                    { définit la largeur du SB.                }
  495.         info^.Dpos := h^^.contrlRect.right - h^^.contrlRect.left - 3*16
  496.     else
  497.         info^.Dpos := h^^.contrlRect.bottom - h^^.contrlRect.top - 3*16;
  498. end;
  499.  
  500.  
  501. (********************************************************************************)
  502. (*                                 THUMBH ACTION                                    *)
  503. (*------------------------------------------------------------------------------*)
  504. (* Suivi du Thumb d'un ScrollBar horizontal, avec mise à jour en continu d'un    *)
  505. (* item affichant la valeur courante.                                            *)
  506. (*                                                                                 *)
  507. (* Les paramètres de l'appel :                                                    *)
  508. (* ---------------------------                                                    *)
  509. (*                                                                                 *)
  510. (*        aucuns paramètres.                                                        *)
  511. (*                                                                                 *)
  512. (********************************************************************************)
  513.  
  514. {$S Main}
  515. procedure thumbHAction;
  516. var    p:        point;
  517.     n:        longint;
  518.     b:         boolean;
  519.     aEvent:    EventRecord;
  520. begin
  521.     getMouse(p);                                    { calcul de la nouvelle valeur    }
  522.     with whichInfo^ do n := longint(oldVal)+longint(Dval)*longint(p.h - oldPos) div longint(Dpos); 
  523.     n := max (n, getCtlMin(whichCtrl));                { par une règle de trois et     }
  524.     n := min (n, getCtlMax(whichCtrl));                { contrainte entre min et max.    }
  525.     if n <> whichInfo^.val then begin                { Si la valeur à changée:        }
  526.         whichInfo^.val := n;                        { mise à jour de la valeur        }
  527.         setDiaNum(myWindow, whichInfo^.disp, n);    { et affichage.                    }
  528.     end;
  529.     if hasWNE then                                    { donne la main aux autres applications }
  530.         b:= WaitNextEvent(everyEvent, aEvent, 0, nil)
  531.     else begin
  532.         SystemTask;
  533.         b:= GetNextEvent(everyEvent, aEvent)
  534.     end;
  535. end;                                                
  536.  
  537.  
  538. (********************************************************************************)
  539. (*                                 THUMBV ACTION                                    *)
  540. (*------------------------------------------------------------------------------*)
  541. (* Suivi du Thumb d'un ScrollBar vertical, avec mise à jour en continu d'un        *)
  542. (* item affichant la valeur courante.                                            *)
  543. (********************************************************************************)
  544.  
  545. {$S Main}
  546. procedure thumbVAction;
  547. var    p:        point;
  548.     n:        longint;
  549.     b:         boolean;
  550.     aEvent:    EventRecord;
  551. begin
  552.     getMouse(p);                                    { calcul de la nouvelle valeur    }
  553.     with whichInfo^ do n := longint(oldVal)+longint(Dval)*longint(p.v - oldPos) div longint(Dpos); 
  554.     n := max (n, getCtlMin(whichCtrl));                { par une règle de trois et     }
  555.     n := min (n, getCtlMax(whichCtrl));                { contrainte entre min et max.    }
  556.     if n <> whichInfo^.val then begin                { Si la valeur à changée:        }
  557.         whichInfo^.val := n;                        { mise à jour de la valeur        }
  558.         setDiaNum(myWindow, whichInfo^.disp, n);    { et affichage.                    }
  559.     end;
  560.     b := GetNextEvent(everyEvent, aEvent)            { pour donner un peu la main    }
  561. end;                                                { aux autres appl.                }
  562.  
  563.  
  564. (********************************************************************************)
  565. (*                                 NORMAL ACTION                                    *)
  566. (*------------------------------------------------------------------------------*)
  567. (* Suivi des autres parties d'un ScrollBar, avec mise à jour en continu d'un    *)
  568. (* item affichant la valeur courante.                                            *)
  569. (*                                                                                 *)
  570. (* Les paramètres de l'appel :                                                    *)
  571. (* ---------------------------                                                    *)
  572. (*                                                                                 *)
  573. (*        aucun paramètre.                                                        *)
  574. (*                                                                                 *)
  575. (********************************************************************************)
  576.  
  577. {$S Main}
  578. procedure normalAction (h: controlHandle; part: integer);
  579. var    n:        integer;
  580.     b:         boolean;
  581.     aEvent:    EventRecord;
  582. begin
  583.     case part of
  584.         inUpButton:     setCtlValue(h,getCtlValue(h)-1);    { on réalise les différents    }
  585.         inDownButton:     setCtlValue(h,getCtlValue(h)+1);    { incréments ou décréments    }
  586.         inPageUp:         setCtlValue(h,getCtlValue(h)-10);    { de la valeur du SB,         }
  587.         inPageDown:     setCtlValue(h,getCtlValue(h)+10);    { suivant la partie cliquée    }
  588.     end;
  589.     if part <> 0 then begin                                    { si une partie est cliquée    }
  590.         n := getCtlValue(h);                                
  591.         if whichInfo^.val <> n then begin                    { et si la valeur du SB à     }
  592.             whichInfo^.val := n;                            { changée, alors on met à    }
  593.             setDiaNum(myWindow, whichInfo^.disp, n);        { jour cette valeur et on    }
  594.         end;                                                { l'affiche.                }
  595.     end;
  596.     b := GetNextEvent(everyEvent, aEvent)                    { pour donner un peu la main}
  597. end;                                                        { aux autres appl.            }
  598.  
  599.  
  600. (********************************************************************************)
  601. (*                                 TRACK DIALOG                                    *)
  602. (*------------------------------------------------------------------------------*)
  603. (* Procédure chargé de trouver le scrollBar selectionné et de déclencher son    *)
  604. (* suivi.                                                                        *)
  605. (*                                                                                 *)
  606. (* Les paramètres de l'appel :                                                    *)
  607. (* ---------------------------                                                    *)
  608. (*                                                                                 *)
  609. (*        w    :    pointeur sur la fenêtre de dialogue.                            *)
  610. (*        p    :    point où la sourie à été clickée.                                *)
  611. (*                                                                                 *)
  612. (********************************************************************************)
  613.  
  614. {$S Main}
  615. procedure TrackDialog(w: windowPtr; p: point);
  616. var
  617.     part,res:    integer;
  618. begin
  619.     GlobalToLocal(p);                                        { conversion du point en local    }
  620.     part := FindControl(p,w,whichCtrl);                        { cherche le SB concerné        }
  621.     if part=0 then exit(trackDialog);                        { si aucun, abandon                }
  622.     whichInfo := TCtrlInfoPtr(getCRefCon(whichCtrl));        { récupere les info de ce SB    }
  623.     if part = inThumb then begin                            { s'il faut suivre le Thumb        }
  624.         whichInfo^.oldVal := getCtlValue(whichCtrl);        { on récupère la valeur actuelle}
  625.         if whichInfo^.mode = 0 then begin                    { pour un SB horizontal:        }
  626.             whichInfo^.oldPos := p.h;                        {  on récupère la position en x    }
  627.             res := trackControl(whichCtrl,p,@thumbHAction)    {  et on suit le Thumb.            }
  628.         end else begin                                        { pour un SB vertical:            }
  629.             whichInfo^.oldPos := p.v;                        {  on récupère la position en y    }            
  630.             res := trackControl(whichCtrl,p,@thumbVAction)    {  et on suit le Thumb.            }
  631.         end;
  632.     end else begin                                            { pour les autres parties:        }
  633.         res := trackControl (whichCtrl,p,@normalAction);    {  on suit normalement            }
  634.     end;
  635. end; 
  636.     
  637.     
  638. (********************************************************************************)
  639. (*                             SET UP WINDOWS                                        *)
  640. (*------------------------------------------------------------------------------*)
  641. (* Procédure chargé d'ouvrir la fenêtre et de réaliser les initialisations         *)
  642. (* necessaires.                                                                    *)
  643. (*                                                                                 *)
  644. (* Les paramètres de l'appel :                                                    *)
  645. (* ---------------------------                                                    *)
  646. (*                                                                                 *)
  647. (*        aucun paramètre.                                                        *)
  648. (*                                                                                 *)
  649. (********************************************************************************)
  650.  
  651. {$S Initialize}
  652. procedure SetUpWindow;
  653. var    r    : rect;
  654. begin    
  655.     with screenBits.bounds do                                    { rect max de déplacmt de fenêtre    }
  656.         SetRect(dragRect, 4, 24, right - 4, bottom - 4);
  657.     myWindow := GetNewDialog(WindowID,nil,pointer(-1));
  658.     SetPort(myWindow);
  659.     r:= myWindow^.portRect;
  660.     with r do begin
  661.         LocalToGlobal(topLeft);
  662.         LocalToGlobal(botRight)
  663.         end;
  664.     if not RectInRgn(r,GetGrayRgn) then begin
  665.         CenterRectOnScreen(r);
  666.         MoveWindow(myWindow,r.left,r.top,true)
  667.         end;
  668.     textFont(Monaco);
  669.     textSize(9);
  670.     textMode(srcCopy);
  671.     SetUpScrollBar(myWindow, @theDelay, DelaySB, DelayTXT, 0);    { réalise les associations    }
  672.     SetUpScrollBar(myWindow, @theVel, VelSB, VelTXT, 0);        { entres les 4 ScrollBars    }
  673.     SetUpScrollBar(myWindow, @thePitch, PitchSB, PitchTXT, 0);    { et les 4 items d'affichage}
  674.     SetUpScrollBar(myWindow, @theChan, ChanSB, ChanTXT, 1);        { du dialogue                }
  675.     theDuration := 50;
  676.     ShowWindow(myWindow)
  677. end;
  678.  
  679. {$S Main}
  680. Procedure SaveWindowPos;
  681. type    rectPtr  =     ^rect;
  682.         rectHdle =    ^rectPtr;
  683. var    windHdle:    handle;
  684. begin
  685.     windHdle:= Get1Resource('DLOG',WindowID);
  686.     rectHdle(windHdle)^^:= windowPeek(myWindow)^.contRgn^^.rgnBBox;
  687.     ChangedResource(windHdle);
  688.     if ResError = noErr then
  689.         WriteResource(windHdle)
  690. end;
  691.     
  692.  
  693. (********************************************************************************)
  694. (*                                 INITIALIZE                                        *)
  695. (*------------------------------------------------------------------------------*)
  696. (* Initialisations générales (hasWNE, foreGround, managers, fenêtre, Midi)        *)
  697. (*                                                                                 *)
  698. (* Les paramètres de l'appel :                                                    *)
  699. (* ---------------------------                                                    *)
  700. (*                                                                                 *)
  701. (*        aucun                                                                    *)
  702. (*                                                                                 *)
  703. (********************************************************************************)
  704.  
  705. {$S Initialize}
  706. Procedure INITIALIZE;
  707. var    err:    OSErr;
  708. begin
  709.     err:= SysEnvirons(1,gMac);
  710.     hasWNE:= (gMac.machineType >= 0) & TrapAvailable(_WaitNextEvent,ToolTrap);
  711.         
  712.     InitGraf(@thePort);                                            { initialisations standard            }
  713.     InitFonts;
  714.     InitWindows;
  715.     InitMenus;
  716.     TEInit;
  717.     InitDialogs(NIL);
  718.     InitCursor;
  719.     SetUpMenus;                                                    { mise en place menus                }
  720.     SetUpMidi;                                                    { ouverture MidiShare                }
  721.     SetUpWindow;                                                { initialisations fenêtre et listes    }
  722. end;
  723.  
  724.  
  725. (********************************************************************************)
  726. (*                                 ADJUST MENUS                                    *)
  727. (*------------------------------------------------------------------------------*)
  728. (* Ajustement de la barre de menus suivant la fenêtre de premier plan, juste    *)
  729. (* lors d'un click dans la barre des menus                                        *)
  730. (*                                                                                 *)
  731. (* Les paramètres de l'appel :                                                    *)
  732. (* ---------------------------                                                    *)
  733. (*                                                                                 *)
  734. (*        aucun                                                                    *)
  735. (*                                                                                 *)
  736. (********************************************************************************)
  737.  
  738. {$S Main}
  739. Procedure ADJUSTMENUS;
  740. begin
  741.     if IsAppWindow(FrontWindow) then begin
  742.         DisableItem(myMenus[EditMenu],UndoI);
  743.         DisableItem(myMenus[EditMenu],CutI);
  744.         DisableItem(myMenus[EditMenu],CopyI);
  745.         DisableItem(myMenus[EditMenu],PasteI);
  746.         DisableItem(myMenus[EditMenu],ClearI)
  747.         end
  748.     else
  749.     if IsDAWindow(FrontWindow) then begin
  750.         EnableItem(myMenus[EditMenu],UndoI);
  751.         EnableItem(myMenus[EditMenu],CutI);
  752.         EnableItem(myMenus[EditMenu],CopyI);
  753.         EnableItem(myMenus[EditMenu],PasteI);
  754.         EnableItem(myMenus[EditMenu],ClearI)
  755.         end
  756. end;
  757.             
  758.  
  759. (********************************************************************************)
  760. (*                                 DO COMMAND                                        *)
  761. (*------------------------------------------------------------------------------*)
  762. (* Gère les menus: Pomme (About), File (Quit)                                    *)
  763. (*                                                                                 *)
  764. (* Les paramètres de l'appel :                                                    *)
  765. (* ---------------------------                                                    *)
  766. (*                                                                                 *)
  767. (*        mResult: numéro de menu et d'item retournés par MenuSelect et MenuKey    *)
  768. (*                                                                                 *)
  769. (********************************************************************************)
  770.  
  771. {$S Main}
  772. Procedure DOCOMMAND ( mResult: LONGINT);
  773. var    theItem:    integer;
  774.     name:        str255;
  775.     sysEdit:    boolean;
  776.     
  777.     Procedure SHOWABOUT;
  778.     var    myDialog    : dialogPtr;
  779.         hit            : integer;
  780.     begin
  781.         myDialog:= GetNewCenteredDialog(AboutID);
  782.         if myDialog <> nil then begin
  783.             ModalDialog(nil,hit);
  784.             DisposDialog(myDialog);
  785.             end
  786.     end;
  787.  
  788. begin    
  789.     theItem := LoWord(mResult);
  790.     case HiWord(mResult) of
  791.         AppleID:                                                { menu Pomme                        }
  792.             if theItem <> 1 then begin
  793.                 GetItem(myMenus[AppleMenu], theItem, name);
  794.                 theItem := OpenDeskAcc(name)  end
  795.             else ShowAbout;
  796.         FileID:                                                    { menu File                            }
  797.             doneFlag := true;
  798.         EditID:                                                    { menu Edit: uniquement pour DAs    }
  799.             sysEdit := SystemEdit(theItem-1);
  800.         end;
  801.     HiliteMenu(0)
  802. end;
  803.         
  804.         
  805. (********************************************************************************)
  806. (*                                 DO MOUSE DOWN                                    *)
  807. (*------------------------------------------------------------------------------*)
  808. (* Gère les clicks souris                                                        *)
  809. (*                                                                                 *)
  810. (* Les paramètres de l'appel :                                                    *)
  811. (* ---------------------------                                                    *)
  812. (*                                                                                 *)
  813. (*        anEvent: l'événement                                                    *)
  814. (*                                                                                 *)
  815. (********************************************************************************)
  816.  
  817. {$S Main}
  818. Procedure DOMOUSEDOWN (anEvent: eventRecord);
  819. var    whichWind:    windowPtr;
  820.     part:        integer;
  821. begin
  822.     part:= FindWindow(anEvent.where, whichWind);
  823.     case part of
  824.         inMenuBar:        begin
  825.                         AdjustMenus;
  826.                         DoCommand(MenuSelect(anEvent.where))
  827.                         end;
  828.         inSysWindow:    SystemClick(anEvent,whichWind);
  829.         inDrag:         DragWindow(whichWind,anEvent.where,dragRect);
  830.         inGoAway:        if IsAppWindow(whichWind) then 
  831.                             doneFlag:= TrackGoAway(whichWind,anEvent.where);
  832.         inContent:        if whichWind <> FrontWindow then
  833.                             SelectWindow(whichWind)
  834.                         else
  835.                             TrackDialog(whichWind,anEvent.where)
  836.         end
  837. end;
  838.  
  839.  
  840. (********************************************************************************)
  841. (*                                 ADJUST CURSOR                                    *)
  842. (*------------------------------------------------------------------------------*)
  843. (* Ajuste le curseur suivant région et fenêtre                                    *)
  844. (*                                                                                 *)
  845. (********************************************************************************)
  846.  
  847. {$S Main}
  848. Procedure ADJUSTCURSOR;
  849. begin
  850.     if foreGround and IsAppWindow(FrontWindow) then
  851.         SetCursor(arrow)
  852. end;
  853.  
  854.  
  855. (********************************************************************************)
  856. (*                                 CLOSE WINDOWS                                    *)
  857. (*------------------------------------------------------------------------------*)
  858. (* Pour terminer correctement l'application: fermeture de toutes les fenêtres    *)
  859. (* (application et DA's)                                                        *)
  860. (*                                                                                 *)
  861. (********************************************************************************)
  862.  
  863. {$S Main}
  864. Procedure CLOSEWIND (aWind: windowPtr);
  865. (* ferme une fenêtre                                                            *)
  866. begin
  867.     if IsDAWindow(aWind) then
  868.         CloseDeskAcc(windowPeek(aWind)^.windowKind)
  869.     else if IsAppWindow(aWind) then
  870.         DisposeWindow(aWind)
  871. end;
  872.  
  873. Procedure CLOSEALLWINDS;
  874. (* ferme toutes les fenêtres                                                    *)
  875. var    window:    windowPtr;
  876. begin
  877.     repeat
  878.         window:= FrontWindow;
  879.         if window <> nil then
  880.             CloseWind(window);
  881.     until window = nil;
  882. end;
  883.  
  884.  
  885. Procedure _DataInit;        EXTERNAL;
  886.  
  887.  
  888. (********************************************************************************)
  889. (*                         Corps principal du programme                            *)
  890. (*------------------------------------------------------------------------------*)
  891. (* Ouverture des différents managers, Initialisations diverses et boucle prin-    *)
  892. (* cipale typique d'une application Macintosh.                                     *)
  893. (********************************************************************************)
  894.     
  895. {$S Main}
  896. begin
  897.     UnLoadSeg(@_DataInit);
  898.     MaxApplZone;
  899.     Initialize;
  900.     UnLoadSeg(@Initialize);
  901.     
  902.     DoneFlag:=false;                                            { flag de terminaison                }
  903.     repeat                                                        { boucle principale typique            }
  904.         if hasWNE then
  905.             eventPending:= WaitNextEvent(everyEvent, myEvent, 0, nil)
  906.                                                                 { no sleep, no mouseRgn                }
  907.         else begin
  908.              SystemTask;
  909.              eventPending:= GetNextEvent(everyEvent, myEvent)
  910.         end;
  911.         AdjustCursor;                                            { si ≠ curseurs ou mouseRgn, ici    }
  912.         with myEvent do
  913.             case what of
  914.                 osEvt:
  915.                     case BSR(message,24) of
  916.                         suspendResumeMessage:
  917.                             begin
  918.                             foreGround:= BAnd(message,resumeMask) <> 0;
  919.                             end;
  920.                     end;
  921.                 keyDown, autoKey:
  922.                     if IsAppWindow(FrontWindow) then begin
  923.                         theChar:= chr(BAnd(message,charCodeMask));
  924.                         IF BAnd(modifiers, cmdKey) <> 0 then
  925.                             DoCommand(MenuKey(theChar))
  926.                     end;
  927.                 mouseDown:
  928.                     DoMouseDown(myEvent);
  929.                 updateEvt:
  930.                     if IsAppWindow(windowPtr(message)) then begin
  931.                         BeginUpdate(windowPtr(message));
  932.                         if not EmptyRgn(windowPtr(message)^.visRgn) then begin
  933.                             SetPort(windowPtr(message));
  934.                             DrawDialog(windowPtr(message));
  935.                         end;
  936.                         EndUpdate(windowPtr(message))
  937.                     end
  938.                 end
  939.     until doneFlag;
  940.     MidiClose(myRefNum);                                                { fermeture MidiShare             }
  941.     SaveWindowPos;
  942.     CloseAllWinds;
  943.     ExitToShell
  944. end.
  945.  
  946.