home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / win3 / edit / muzika / objclass.cpp < prev    next >
C/C++ Source or Header  |  1992-07-21  |  23KB  |  912 lines

  1. // **********************************************
  2. // File: OBJCLASS.CPP
  3. // Musical objects library
  4.  
  5. #include "muzika.h"
  6. #include "objects.h"
  7. #include <string.h>
  8.  
  9. // **********************************************
  10. // LoadObject loads an object from a file.
  11. // It reads the object type and constructs the appropriate object,
  12. // letting it to go on and load its data (using the version of the constructor
  13. // with an input stream as a parameter). The type of the object
  14. // (point or continuous) is returned in *type.
  15.  
  16. MusicalObject *LoadObject(istream &in, void (*LoadError)(), int *type)
  17. {
  18.   // Identify the object type
  19.   switch (in.get()) {
  20.     case O_NOTE:
  21.       *type = POINTOBJECT;
  22.       return new Note(in);
  23.  
  24.     case O_PAUSE:
  25.       *type = POINTOBJECT;
  26.       return new Pause(in);
  27.  
  28.     case O_KEY:
  29.       *type = POINTOBJECT;
  30.       return new Key(in);
  31.  
  32.     case O_BEAT:
  33.       *type = POINTOBJECT;
  34.       return new Beat(in);
  35.  
  36.     case O_BAR:
  37.       *type = POINTOBJECT;
  38.       return new Bar(in);
  39.  
  40.     case O_LOUDNESS:
  41.       *type = POINTOBJECT;
  42.       return new Loudness(in);
  43.  
  44.     case O_CRESCENDO:
  45.       *type = CONTINUOUSOBJECT;
  46.       return new Crescendo(in);
  47.  
  48.     case O_TEXT:
  49.       *type = POINTOBJECT;
  50.       return new Text(in);
  51.   }
  52.  
  53.   // Unknown object: call error function
  54.   (*LoadError)();
  55.   return NULL;
  56. }
  57.  
  58. // **********************************************
  59. // PasteObject creates an object from a clipboard entry.
  60. // It reads the object type and constructs the appropriate object,
  61. // letting it to go on and load its data (using the version of the constructor
  62. // with a far char pointer as a parameter). The type of the object
  63. // (point or continuous) is returned in *type.
  64.  
  65. MusicalObject *PasteObject(void far *&clipboard, int *type)
  66. {
  67.   // Identify the object type
  68.   switch (*((char far *) clipboard)++) {
  69.     case O_NOTE:
  70.       *type = POINTOBJECT;
  71.       return new Note(clipboard);
  72.  
  73.     case O_PAUSE:
  74.       *type = POINTOBJECT;
  75.       return new Pause(clipboard);
  76.  
  77.     case O_KEY:
  78.       *type = POINTOBJECT;
  79.       return new Key(clipboard);
  80.  
  81.     case O_BEAT:
  82.       *type = POINTOBJECT;
  83.       return new Beat(clipboard);
  84.  
  85.     case O_BAR:
  86.       *type = POINTOBJECT;
  87.       return new Bar(clipboard);
  88.  
  89.     case O_LOUDNESS:
  90.       *type = POINTOBJECT;
  91.       return new Loudness(clipboard);
  92.  
  93.     case O_CRESCENDO:
  94.       *type = CONTINUOUSOBJECT;
  95.       return new Crescendo(clipboard);
  96.  
  97.     case O_TEXT:
  98.       *type = POINTOBJECT;
  99.       return new Text(clipboard);
  100.   }
  101.  
  102.   // Unknown object: return a null pointer
  103.   return NULL;
  104. }
  105.  
  106. // **********************************************
  107. // Following are the member functions of the various musical objects,
  108. // all derived from the MusicalObject base class, either via
  109. // PointObject or ContinuousObject. The following functions
  110. // are defined for each musical object type:
  111. // - A constructor from direct object data
  112. // - A constructor from an input stream (reads the object data from the stream)
  113. // - A constructor from the clipboard (reads the object data from memory)
  114. // - Draw draws the object in the given display context, using the global variables
  115. //   staffX, staffY, staffLoc, and currStaffHeight (from DISPLAY.CPP) when needed.
  116. // - Format sets the object in the given X coordinate during formatting.
  117. // - MIDIPlay writes the MIDI event described by the object to the given file.
  118. // - printOn writes the object data to the given file (when the melody is saved).
  119. // - clipOn writes the object data in the clipboard (when the object is cut or copied).
  120. //
  121. // Any new objects in future extensions should be added here,
  122. // and define their versions of all the above functions.
  123.  
  124. // **********************************************
  125. // Definitions of the Note class member functions
  126.  
  127. Note :: Note(int X, int Y, int duration)
  128. {
  129.   // Copy the given parameters to the object variables
  130.   _location = INSTAFF;
  131.   _X = X;
  132.   _Y = (Y >= 0) ? (Y+1)/3*3 : -((1-Y)/3*3);
  133.   _duration = duration;
  134. }
  135.  
  136. Note :: Note(istream &in)
  137. {
  138.   _location = INSTAFF;
  139.  
  140.   // Read the object data from the stream
  141.   in.read((char *) &_X, sizeof(_X));
  142.   in.read((char *) &_Y, sizeof(_Y));
  143.   in.read((char *) &_duration, sizeof(_duration));
  144. }
  145.  
  146. Note :: Note(void far *&clipboard)
  147. {
  148.   int far *&iclip = (int far *) clipboard;
  149.   _location = INSTAFF;
  150.  
  151.   // Read the object data from the clipboard entry
  152.   _X = *iclip++;
  153.   _Y = *iclip++;
  154.   _duration = *iclip++;
  155. }
  156.  
  157. void Note :: Draw(HDC hDC)
  158. {
  159.   // Draw the staff extension lines if necessary
  160.   if (_Y < 0)
  161.     for (int y = -6; y >= _Y; y -= 6) {
  162.       MoveTo(hDC, _X+staffX-5, staffY+y);
  163.       LineTo(hDC, _X+staffX+6, staffY+y);
  164.     }
  165.   if (_Y > 24)
  166.     for (int y = 30; y <= _Y; y += 6) {
  167.       MoveTo(hDC, _X+staffX-5, staffY+y);
  168.       LineTo(hDC, _X+staffX+6, staffY+y);
  169.     }
  170.  
  171.   // Load the appropriate bitmap
  172.   HDC hBitmapDC = CreateCompatibleDC(hDC);
  173.   HBITMAP hBitmap;
  174.   int yCenter;
  175.   switch (_duration) {
  176.     case FULLDURATION:
  177.       hBitmap = LoadBitmap(hInst, "B_FULLNOTE");
  178.       yCenter = 10;
  179.       break;
  180.  
  181.     case HALFDURATION:
  182.       if (_Y > 12) {
  183.         hBitmap = LoadBitmap(hInst, "B_HALFNOTEUP");
  184.         yCenter = 15;
  185.       }
  186.       else
  187.       {
  188.         hBitmap = LoadBitmap(hInst, "B_HALFNOTE");
  189.         yCenter = 4;
  190.       }
  191.       break;
  192.  
  193.     case QUARTERDURATION:
  194.       if (_Y > 12) {
  195.         hBitmap = LoadBitmap(hInst, "B_QUARTERNOTEUP");
  196.         yCenter = 15;
  197.       }
  198.       else
  199.       {
  200.         hBitmap = LoadBitmap(hInst, "B_QUARTERNOTE");
  201.         yCenter = 4;
  202.       }
  203.       break;
  204.  
  205.     case EIGHTHDURATION:
  206.       if (_Y > 12) {
  207.         hBitmap = LoadBitmap(hInst, "B_EIGHTHNOTEUP");
  208.         yCenter = 15;
  209.       }
  210.       else
  211.       {
  212.         hBitmap = LoadBitmap(hInst, "B_EIGHTHNOTE");
  213.         yCenter = 4;
  214.       }
  215.       break;
  216.  
  217.     case SIXTEENTHDURATION:
  218.       if (_Y > 12) {
  219.         hBitmap = LoadBitmap(hInst, "B_SIXTEENTHNOTEUP");
  220.         yCenter = 15;
  221.       }
  222.       else
  223.       {
  224.         hBitmap = LoadBitmap(hInst, "B_SIXTEENTHNOTE");
  225.         yCenter = 4;
  226.       }
  227.       break;
  228.   }
  229.  
  230.   // Draw the bitmap
  231.   HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
  232.   BitBlt(hDC, _X+staffX-16, _Y+staffY-yCenter, 32, 20, hBitmapDC, 0, 0, SRCAND);
  233.   SelectObject(hBitmapDC, hOldBitmap);
  234.   DeleteDC(hBitmapDC);
  235.   DeleteObject(hBitmap);
  236. }
  237.  
  238. void Note :: Format(int &X)
  239. {
  240.   // No special actions required: just copy the X coordinate
  241.   _X = X;
  242. }
  243.  
  244. void Note :: MIDIPlay(ostream &out, int part)
  245. {
  246.   // Write a Note On event in the temporary file
  247.   // with the correct frequency and duration
  248.   static const noteNumber[7] = {0, 2, 4, 5, 7, 9, 11};
  249.   out.put(0x90+part);
  250.   int octave = (30-_Y)/21;
  251.   int freq = (30-21*octave-_Y)/3;
  252.   out.write((char *) &_duration, sizeof(int));
  253.   out.put(12*(octave+4)+noteNumber[freq]);
  254.   out.put(0x40);
  255. }
  256.  
  257. void Note :: printOn(ostream &out) const
  258. {
  259.   // Write the object type ID (O_NOTE) and data to the stream
  260.   out.put(O_NOTE);
  261.   out.write((char *) &_X, sizeof(_X));
  262.   out.write((char *) &_Y, sizeof(_Y));
  263.   out.write((char *) &_duration, sizeof(_duration));
  264. }
  265.  
  266. void Note :: clipOn(void far *&clipboard) const
  267. {
  268.   char far *&bclip = (char far *) clipboard;
  269.   int far *&iclip = (int far *) clipboard;
  270.  
  271.   // Write the object type ID (O_NOTE) and data to the clipboard entry
  272.   *bclip++ = O_NOTE;
  273.   *iclip++ = _X;
  274.   *iclip++ = _Y;
  275.   *iclip++ = _duration;
  276. }
  277.  
  278. // **********************************************
  279. // Definitions of the Pause class member functions
  280.  
  281. Pause :: Pause(int X, int duration)
  282. {
  283.   // Copy the given parameters to the object variables
  284.   _location = INSTAFF;
  285.   _X = X;
  286.   _duration = duration;
  287. }
  288.  
  289. Pause :: Pause(istream &in)
  290. {
  291.   _location = INSTAFF;
  292.  
  293.   // Read the object data from the stream
  294.   in.read((char *) &_X, sizeof(_X));
  295.   in.read((char *) &_duration, sizeof(_duration));
  296. }
  297.  
  298. Pause :: Pause(void far *&clipboard)
  299. {
  300.   int far *&iclip = (int far *) clipboard;
  301.   _location = INSTAFF;
  302.  
  303.   // Read the object data from the clipboard entry
  304.   _X = *iclip++;
  305.   _duration = *iclip++;
  306. }
  307.  
  308. void Pause :: Draw(HDC hDC)
  309. {
  310.   // Draw the pause bitmap according to duration
  311.   switch (_duration) {
  312.     case FULLDURATION:
  313.       Rectangle(hDC, _X+staffX-5, staffY+7, _X+staffX+5, staffY+9);
  314.       break;
  315.  
  316.     case HALFDURATION:
  317.       Rectangle(hDC, _X+staffX-5, staffY+10, _X+staffX+5, staffY+12);
  318.       break;
  319.  
  320.     default:
  321.       HDC hBitmapDC = CreateCompatibleDC(hDC);
  322.       HBITMAP hBitmap;
  323.       switch (_duration) {
  324.         case QUARTERDURATION:
  325.           hBitmap = LoadBitmap(hInst, "B_QUARTERPAUSE");
  326.           break;
  327.  
  328.         case EIGHTHDURATION:
  329.           hBitmap = LoadBitmap(hInst, "B_EIGHTHPAUSE");
  330.           break;
  331.  
  332.         case SIXTEENTHDURATION:
  333.           hBitmap = LoadBitmap(hInst, "B_SIXTEENTHPAUSE");
  334.           break;
  335.       }
  336.       HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
  337.       BitBlt(hDC, _X+staffX-16, staffY+2, 32, 20, hBitmapDC, 0, 0, SRCAND);
  338.       SelectObject(hBitmapDC, hOldBitmap);
  339.       DeleteDC(hBitmapDC);
  340.       DeleteObject(hBitmap);
  341.       break;
  342.   }
  343. }
  344.  
  345. void Pause :: Format(int &X)
  346. {
  347.   // No special actions required: just copy the X coordinate
  348.   _X = X;
  349. }
  350.  
  351. void Pause :: MIDIPlay(ostream &out, int part)
  352. {
  353.   // Put a Note Off event with the correct duration in the temporary file
  354.   out.put(0x80+part);
  355.   out.write((char *) &_duration, sizeof(int));
  356. }
  357.  
  358. void Pause :: printOn(ostream &out) const
  359. {
  360.   // Write the object type ID (O_PAUSE) and data to the stream
  361.   out.put(O_PAUSE);
  362.   out.write((char *) &_X, sizeof(_X));
  363.   out.write((char *) &_duration, sizeof(_duration));
  364. }
  365.  
  366. void Pause :: clipOn(void far *&clipboard) const
  367. {
  368.   char far *&bclip = (char far *) clipboard;
  369.   int far *&iclip = (int far *) clipboard;
  370.  
  371.   // Write the object type ID (O_PAUSE) and data to the clipboard entry
  372.   *bclip++ = O_PAUSE;
  373.   *iclip++ = _X;
  374.   *iclip++ = _duration;
  375. }
  376.  
  377. // **********************************************
  378. // Definitions of the Key class member functions
  379.  
  380. Key :: Key(int, int type)
  381. {
  382.   // Copy the given parameters to the object variables
  383.   _location = INSTAFF | ONEPERSTAFF;
  384.   _X = LOCATION;
  385.   _type = type;
  386. }
  387.  
  388. Key :: Key(istream &in)
  389. {
  390.   _location = INSTAFF | ONEPERSTAFF;
  391.   _X = LOCATION;
  392.  
  393.   // Read the object data from the stream
  394.   in.read((char *) &_type, sizeof(_type));
  395. }
  396.  
  397. Key :: Key(void far *&clipboard)
  398. {
  399.   int far *&iclip = (int far *) clipboard;
  400.   _location = INSTAFF | ONEPERSTAFF;
  401.   _X = LOCATION;
  402.  
  403.   // Read the object data from the clipboard entry
  404.   _type = *iclip++;
  405. }
  406.  
  407. void Key :: Draw(HDC hDC)
  408. {
  409.   HDC hBitmapDC = CreateCompatibleDC(hDC);
  410.   HBITMAP hBitmap;
  411.  
  412.   // Load the appropriate bitmap
  413.   switch (_type) {
  414.     case KEYSOL:
  415.       hBitmap = LoadBitmap(hInst, "B_KEYSOL");
  416.       break;
  417.  
  418.     case KEYFA:
  419.       hBitmap = LoadBitmap(hInst, "B_KEYFA");
  420.       break;
  421.   }
  422.  
  423.   // Draw the bitmap
  424.   HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
  425.   BitBlt(hDC, _X+staffX-16, staffY+4, 32, 20, hBitmapDC,
  426.     0, 0, SRCAND);
  427.   SelectObject(hBitmapDC, hOldBitmap);
  428.   DeleteDC(hBitmapDC);
  429.   DeleteObject(hBitmap);
  430. }
  431.  
  432. void Key :: Format(int &)
  433. {
  434.   // Keys cannot be formatted
  435. }
  436.  
  437. void Key :: printOn(ostream &out) const
  438. {
  439.   // Write the object type ID (O_KEY) and data to the stream
  440.   out.put(O_KEY);
  441.   out.write((char *) &_type, sizeof(_type));
  442. }
  443.  
  444. void Key :: clipOn(void far *&clipboard) const
  445. {
  446.   char far *&bclip = (char far *) clipboard;
  447.   int far *&iclip = (int far *) clipboard;
  448.  
  449.   // Write the object type ID (O_KEY) to the clipboard entry
  450.   *bclip++ = O_KEY;
  451.   *iclip++ = _type;
  452. }
  453.  
  454. // **********************************************
  455. // Definitions of the Beat class member functions
  456.  
  457. Beat :: Beat(int X, int type)
  458. {
  459.   // Copy the given parameters to the object variables
  460.   _location = COMMONMULTIPLE;
  461.   _X = X;
  462.   _type = type;
  463. }
  464.  
  465. Beat :: Beat(istream &in)
  466. {
  467.   _location = COMMONMULTIPLE;
  468.  
  469.   // Read the object data from the stream
  470.   in.read((char *) &_X, sizeof(_X));
  471.   in.read((char *) &_type, sizeof(_type));
  472. }
  473.  
  474. Beat :: Beat(void far *&clipboard)
  475. {
  476.   int far *&iclip = (int far *) clipboard;
  477.   _location = COMMONMULTIPLE;
  478.  
  479.   // Read the object data from the clipboard entry
  480.   _X = *iclip++;
  481.   _type = *iclip++;
  482. }
  483.  
  484. void Beat :: Draw(HDC hDC)
  485. {
  486.   HDC hBitmapDC = CreateCompatibleDC(hDC);
  487.   HBITMAP hBitmap;
  488.  
  489.   // Load the appropriate bitmap
  490.   switch (_type) {
  491.     case BEATC:
  492.       hBitmap = LoadBitmap(hInst, "B_BEATC");
  493.       break;
  494.  
  495.     case BEATCBAR:
  496.       hBitmap = LoadBitmap(hInst, "B_BEATCBAR");
  497.       break;
  498.  
  499.     case BEAT28:
  500.       hBitmap = LoadBitmap(hInst, "B_BEAT28");
  501.       break;
  502.  
  503.     case BEAT24:
  504.       hBitmap = LoadBitmap(hInst, "B_BEAT24");
  505.       break;
  506.  
  507.     case BEAT38:
  508.       hBitmap = LoadBitmap(hInst, "B_BEAT38");
  509.       break;
  510.  
  511.     case BEAT34:
  512.       hBitmap = LoadBitmap(hInst, "B_BEAT34");
  513.       break;
  514.  
  515.     case BEAT48:
  516.       hBitmap = LoadBitmap(hInst, "B_BEAT48");
  517.       break;
  518.  
  519.     case BEAT44:
  520.       hBitmap = LoadBitmap(hInst, "B_BEAT44");
  521.       break;
  522.  
  523.     case BEAT68:
  524.       hBitmap = LoadBitmap(hInst, "B_BEAT68");
  525.       break;
  526.  
  527.   }
  528.  
  529.   // Draw the bitmap
  530.   HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
  531.   BitBlt(hDC, _X+staffX-16, staffY+4, 32, 20, hBitmapDC,
  532.     0, 0, SRCAND);
  533.   SelectObject(hBitmapDC, hOldBitmap);
  534.   DeleteDC(hBitmapDC);
  535.   DeleteObject(hBitmap);
  536. }
  537.  
  538. void Beat :: Format(int &X)
  539. {
  540.   // No special actions required: just copy the X coordinate
  541.   _X = X;
  542. }
  543.  
  544. void Beat :: printOn(ostream &out) const
  545. {
  546.   // Write the object type ID (O_BEAT) and data to the stream
  547.   out.put(O_BEAT);
  548.   out.write((char *) &_X, sizeof(_X));
  549.   out.write((char *) &_type, sizeof(_type));
  550. }
  551.  
  552. void Beat :: clipOn(void far *&clipboard) const
  553. {
  554.   char far *&bclip = (char far *) clipboard;
  555.   int far *&iclip = (int far *) clipboard;
  556.  
  557.   // Write the object type ID (O_BEAT) and data to the clipboard entry
  558.   *bclip++ = O_BEAT;
  559.   *iclip++ = _X;
  560.   *iclip++ = _type;
  561. }
  562.  
  563. // **********************************************
  564. // Definitions of the Bar class member functions
  565.  
  566. Bar :: Bar(int X, int type)
  567. {
  568.   // Choose the _location attribute value according to bar type
  569.   switch (_type = type) {
  570.     case STARTBAR:
  571.       _location = COMMONMULTIPLE | ONEPERSTAFF;
  572.       _X = 0;
  573.       break;
  574.  
  575.     case ENDBAR:
  576.       _location = COMMONMULTIPLE | ONEPERSTAFF;
  577.       _X = melody.GetStaffWidth();
  578.       break;
  579.  
  580.     default:
  581.       _location = COMMONMULTIPLE;
  582.       _X = X;
  583.       break;
  584.   }
  585. }
  586.  
  587. Bar :: Bar(istream &in)
  588. {
  589.   _location = COMMONMULTIPLE;
  590.  
  591.   // Read the object data from the stream
  592.   in.read((char *) &_X, sizeof(_X));
  593.   in.read((char *) &_type, sizeof(_type));
  594.  
  595.   // Decide about the object _location attribute value according to type
  596.   if (_type == STARTBAR || _type == ENDBAR)
  597.     _location |= ONEPERSTAFF;
  598. }
  599.  
  600. Bar :: Bar(void far *&clipboard)
  601. {
  602.   int far *&iclip = (int far *) clipboard;
  603.   _location = COMMONMULTIPLE;
  604.  
  605.   // Read the object data from the clipboard entry
  606.   _X = *iclip++;
  607.   _type = *iclip++;
  608.  
  609.   // Decide about the _location attribute value according to type
  610.   if (_type == STARTBAR || _type == ENDBAR)
  611.     _location |= ONEPERSTAFF;
  612. }
  613.  
  614. void Bar :: Draw(HDC hDC)
  615. {
  616.   HBRUSH hOldBrush = SelectObject(hDC, GetStockObject(BLACK_BRUSH));
  617.   int Yfrom, Yto;
  618.  
  619.   // Calculate the bar height limits
  620.   Yfrom = staffY;
  621.   switch (staffLoc) {
  622.     case SINGLESTAFF:
  623.     case LASTSTAFF:
  624.       Yto = staffY+24;
  625.       break;
  626.  
  627.     case FIRSTSTAFF:
  628.     case MIDSTAFF:
  629.       Yto = staffY+currStaffHeight;
  630.       break;
  631.   }
  632.  
  633.   // Draw the appropriate bar pattern
  634.   switch (_type) {
  635.     case BAR:
  636.       MoveTo(hDC, _X+staffX, Yfrom);
  637.       LineTo(hDC, _X+staffX, Yto);
  638.       break;
  639.  
  640.     case DOUBLEBAR:
  641.       MoveTo(hDC, _X+staffX-2, Yfrom);
  642.       LineTo(hDC, _X+staffX-2, Yto);
  643.       MoveTo(hDC, _X+staffX+2, Yfrom);
  644.       LineTo(hDC, _X+staffX+2, Yto);
  645.       break;
  646.  
  647.     case STARTBAR:
  648.       Rectangle(hDC, _X+staffX, Yfrom, _X+staffX+4, Yto);
  649.       MoveTo(hDC, _X+staffX+6, Yfrom);
  650.       LineTo(hDC, _X+staffX+6, Yto);
  651.       break;
  652.  
  653.     case ENDBAR:
  654.       Rectangle(hDC, _X+staffX-3, Yfrom, _X+staffX+1, Yto);
  655.       MoveTo(hDC, _X+staffX-6, Yfrom);
  656.       LineTo(hDC, _X+staffX-6, Yto);
  657.       break;
  658.   }
  659.  
  660.   SelectObject(hDC, hOldBrush);
  661. }
  662.  
  663. void Bar :: Format(int &X)
  664. {
  665.   // Bar can be moved unless it is fixed at the start or end of the staff
  666.   if (_type != STARTBAR && _type != ENDBAR)
  667.     _X = X;
  668. }
  669.  
  670. void Bar :: printOn(ostream &out) const
  671. {
  672.   // Write the object type ID (O_BAR) and data to the stream
  673.   out.put(O_BAR);
  674.   out.write((char *) &_X, sizeof(_X));
  675.   out.write((char *) &_type, sizeof(_type));
  676. }
  677.  
  678. void Bar :: clipOn(void far *&clipboard) const
  679. {
  680.   char far *&bclip = (char far *) clipboard;
  681.   int far *&iclip = (int far *) clipboard;
  682.  
  683.   // Write the object type ID (O_BAR) and data to the clipboard entry
  684.   *bclip++ = O_BAR;
  685.   *iclip++ = _X;
  686.   *iclip++ = _type;
  687. }
  688.  
  689. // **********************************************
  690. // Definitions of the Loudness class member functions
  691.  
  692. Loudness :: Loudness(int X, int loudness)
  693. {
  694.   // Copy the given parameters to the object variables
  695.   _location = BELOWMULTIPLE;
  696.   _X = X;
  697.   _loudness = loudness;
  698. }
  699.  
  700. Loudness :: Loudness(istream &in)
  701. {
  702.   _location = BELOWMULTIPLE;
  703.  
  704.   // Read the object data from the stream
  705.   in.read((char *) &_X, sizeof(_X));
  706.   in.read((char *) &_loudness, sizeof(_loudness));
  707. }
  708.  
  709. Loudness :: Loudness(void far *&clipboard)
  710. {
  711.   int far *&iclip = (int far *) clipboard;
  712.   _location = BELOWMULTIPLE;
  713.  
  714.   // Read the object data from the clipboard entry
  715.   _X = *iclip++;
  716.   _loudness = *iclip++;
  717. }
  718.  
  719. void Loudness :: Draw(HDC hDC)
  720. {
  721.   HDC hBitmapDC = CreateCompatibleDC(hDC);
  722.   HBITMAP hBitmap;
  723.  
  724.   // Load the appropriate bitmap
  725.   switch (_loudness) {
  726.     case FORTE:
  727.       hBitmap = LoadBitmap(hInst, "B_FORTE");
  728.       break;
  729.  
  730.     case FORTISSIMO:
  731.       hBitmap = LoadBitmap(hInst, "B_FORTISSIMO");
  732.       break;
  733.  
  734.     case PIANO:
  735.       hBitmap = LoadBitmap(hInst, "B_PIANO");
  736.       break;
  737.  
  738.     case PIANISSIMO:
  739.       hBitmap = LoadBitmap(hInst, "B_PIANISSIMO");
  740.       break;
  741.   }
  742.  
  743.   // Draw the bitmap
  744.   HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
  745.   BitBlt(hDC, _X+staffX-16, staffY+currStaffHeight/2-8, 32, 20, hBitmapDC,
  746.     0, 0, SRCAND);
  747.   SelectObject(hBitmapDC, hOldBitmap);
  748.   DeleteDC(hBitmapDC);
  749.   DeleteObject(hBitmap);
  750. }
  751.  
  752. void Loudness :: Format(int &X)
  753. {
  754.   // No special actions required: just copy the X coordinate
  755.   _X = X;
  756. }
  757.  
  758. void Loudness :: printOn(ostream &out) const
  759. {
  760.   // Write the object type ID (O_LOUDNESS) and data to the stream
  761.   out.put(O_LOUDNESS);
  762.   out.write((char *) &_X, sizeof(_X));
  763.   out.write((char *) &_loudness, sizeof(_loudness));
  764. }
  765.  
  766. void Loudness :: clipOn(void far *&clipboard) const
  767. {
  768.   char far *&bclip = (char far *) clipboard;
  769.   int far *&iclip = (int far *) clipboard;
  770.  
  771.   // Write the object type ID (O_LOUDNESS) and data to the clipboard entry
  772.   *bclip++ = O_LOUDNESS;
  773.   *iclip++ = _X;
  774.   *iclip++ = _loudness;
  775. }
  776.  
  777. // **********************************************
  778. // Definitions of the Crescendo class member functions
  779.  
  780. Crescendo :: Crescendo(int Xleft, int Xright, int direction)
  781. {
  782.   // Copy the given parameters to the object variables
  783.   _location = BELOWMULTIPLE;
  784.   _Xleft = Xleft;
  785.   _Xright = Xright;
  786.   _direction = direction;
  787. }
  788.  
  789. Crescendo :: Crescendo(istream &in)
  790. {
  791.   _location = BELOWMULTIPLE;
  792.  
  793.   // Read the object data from the stream
  794.   in.read((char *) &_Xleft, sizeof(_Xleft));
  795.   in.read((char *) &_Xright, sizeof(_Xright));
  796.   in.read((char *) &_direction, sizeof(_direction));
  797. }
  798.  
  799. Crescendo :: Crescendo(void far *&clipboard)
  800. {
  801.   int far *&iclip = (int far *) clipboard;
  802.   _location = BELOWMULTIPLE;
  803.  
  804.   // Read the object data from the clipboard entry
  805.   _Xleft = *iclip++;
  806.   _Xright = *iclip++;
  807.   _direction = *iclip++;
  808. }
  809.  
  810. void Crescendo :: Draw(HDC hDC)
  811. {
  812.   // Draw the pair of lines according to direction
  813.   MoveTo(hDC, staffX+((_direction == CRESCENDO) ? _Xright : _Xleft),
  814.     staffY+currStaffHeight/2+4);
  815.   LineTo(hDC, staffX+((_direction == CRESCENDO) ? _Xleft : _Xright),
  816.     staffY+currStaffHeight/2+8);
  817.   LineTo(hDC, staffX+((_direction == CRESCENDO) ? _Xright : _Xleft),
  818.     staffY+currStaffHeight/2+12);
  819. }
  820.  
  821. void Crescendo :: printOn(ostream &out) const
  822. {
  823.   // Write the object type ID (O_CRESCENDO) and data to the stream
  824.   out.put(O_CRESCENDO);
  825.   out.write((char *) &_Xleft, sizeof(_Xleft));
  826.   out.write((char *) &_Xright, sizeof(_Xright));
  827.   out.write((char *) &_direction, sizeof(_direction));
  828. }
  829.  
  830. void Crescendo :: clipOn(void far *&clipboard) const
  831. {
  832.   char far *&bclip = (char far *) clipboard;
  833.   int far *&iclip = (int far *) clipboard;
  834.  
  835.   // Write the object type ID (O_CRESCENDO) and data to the clipboard entry
  836.   *bclip++ = O_CRESCENDO;
  837.   *iclip++ = _Xleft;
  838.   *iclip++ = _Xright;
  839.   *iclip++ = _direction;
  840. }
  841.  
  842. // **********************************************
  843. // Definitions of the Text class member functions
  844.  
  845. Text :: Text(int X, int Y, char *string)
  846. {
  847.   // Copy the given parameters to the object variables
  848.   _location = INSTAFF;
  849.   _X = X;
  850.   _Y = (Y > 12) ? 30 : -21;
  851.   strcpy(_text, string);
  852. }
  853.  
  854. Text :: Text(istream &in)
  855. {
  856.   _location = INSTAFF;
  857.  
  858.   // Read the object data from the stream
  859.   in.read((char *) &_X, sizeof(_X));
  860.   in.read((char *) &_Y, sizeof(_Y));
  861.   in.get(_text, MAXTEXT+1, 0);
  862.   in.get();
  863. }
  864.  
  865. Text :: Text(void far *&clipboard)
  866. {
  867.   _location = INSTAFF;
  868.   char far *&bclip = (char far *) clipboard;
  869.   int far *&iclip = (int far *) clipboard;
  870.  
  871.   // Read the object data from the clipboard entry
  872.   _X = *iclip++;
  873.   _Y = *iclip++;
  874.   _fstrcpy(_text, bclip);
  875.   bclip += _fstrlen(bclip)+1;
  876. }
  877.  
  878. void Text :: Draw(HDC hDC)
  879. {
  880.   // Put the text in a transparent fashion (i.e. not erasing the background)
  881.   SetBkMode(hDC, TRANSPARENT);
  882.   TextOut(hDC, _X+staffX, _Y+staffY, _text, strlen(_text));
  883. }
  884.  
  885. void Text :: Format(int &X)
  886. {
  887.   // No special actions required: just copy the X coordinate
  888.   _X = X;
  889. }
  890.  
  891. void Text :: printOn(ostream &out) const
  892. {
  893.   // Write the object type ID (O_TEXT) and data to the stream
  894.   out.put(O_TEXT);
  895.   out.write((char *) &_X, sizeof(_X));
  896.   out.write((char *) &_Y, sizeof(_Y));
  897.   out.write(_text, strlen(_text)+1);
  898. }
  899.  
  900. void Text :: clipOn(void far *&clipboard) const
  901. {
  902.   char far *&bclip = (char far *) clipboard;
  903.   int far *&iclip = (int far *) clipboard;
  904.  
  905.   // Write the object type ID (O_TEXT) and data to the clipboard entry
  906.   *bclip++ = O_TEXT;
  907.   *iclip++ = _X;
  908.   *iclip++ = _Y;
  909.   _fstrcpy(bclip, _text);
  910.   bclip += strlen(_text)+1;
  911. }
  912.