home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
win3
/
edit
/
muzika
/
objclass.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-21
|
23KB
|
912 lines
// **********************************************
// File: OBJCLASS.CPP
// Musical objects library
#include "muzika.h"
#include "objects.h"
#include <string.h>
// **********************************************
// LoadObject loads an object from a file.
// It reads the object type and constructs the appropriate object,
// letting it to go on and load its data (using the version of the constructor
// with an input stream as a parameter). The type of the object
// (point or continuous) is returned in *type.
MusicalObject *LoadObject(istream &in, void (*LoadError)(), int *type)
{
// Identify the object type
switch (in.get()) {
case O_NOTE:
*type = POINTOBJECT;
return new Note(in);
case O_PAUSE:
*type = POINTOBJECT;
return new Pause(in);
case O_KEY:
*type = POINTOBJECT;
return new Key(in);
case O_BEAT:
*type = POINTOBJECT;
return new Beat(in);
case O_BAR:
*type = POINTOBJECT;
return new Bar(in);
case O_LOUDNESS:
*type = POINTOBJECT;
return new Loudness(in);
case O_CRESCENDO:
*type = CONTINUOUSOBJECT;
return new Crescendo(in);
case O_TEXT:
*type = POINTOBJECT;
return new Text(in);
}
// Unknown object: call error function
(*LoadError)();
return NULL;
}
// **********************************************
// PasteObject creates an object from a clipboard entry.
// It reads the object type and constructs the appropriate object,
// letting it to go on and load its data (using the version of the constructor
// with a far char pointer as a parameter). The type of the object
// (point or continuous) is returned in *type.
MusicalObject *PasteObject(void far *&clipboard, int *type)
{
// Identify the object type
switch (*((char far *) clipboard)++) {
case O_NOTE:
*type = POINTOBJECT;
return new Note(clipboard);
case O_PAUSE:
*type = POINTOBJECT;
return new Pause(clipboard);
case O_KEY:
*type = POINTOBJECT;
return new Key(clipboard);
case O_BEAT:
*type = POINTOBJECT;
return new Beat(clipboard);
case O_BAR:
*type = POINTOBJECT;
return new Bar(clipboard);
case O_LOUDNESS:
*type = POINTOBJECT;
return new Loudness(clipboard);
case O_CRESCENDO:
*type = CONTINUOUSOBJECT;
return new Crescendo(clipboard);
case O_TEXT:
*type = POINTOBJECT;
return new Text(clipboard);
}
// Unknown object: return a null pointer
return NULL;
}
// **********************************************
// Following are the member functions of the various musical objects,
// all derived from the MusicalObject base class, either via
// PointObject or ContinuousObject. The following functions
// are defined for each musical object type:
// - A constructor from direct object data
// - A constructor from an input stream (reads the object data from the stream)
// - A constructor from the clipboard (reads the object data from memory)
// - Draw draws the object in the given display context, using the global variables
// staffX, staffY, staffLoc, and currStaffHeight (from DISPLAY.CPP) when needed.
// - Format sets the object in the given X coordinate during formatting.
// - MIDIPlay writes the MIDI event described by the object to the given file.
// - printOn writes the object data to the given file (when the melody is saved).
// - clipOn writes the object data in the clipboard (when the object is cut or copied).
//
// Any new objects in future extensions should be added here,
// and define their versions of all the above functions.
// **********************************************
// Definitions of the Note class member functions
Note :: Note(int X, int Y, int duration)
{
// Copy the given parameters to the object variables
_location = INSTAFF;
_X = X;
_Y = (Y >= 0) ? (Y+1)/3*3 : -((1-Y)/3*3);
_duration = duration;
}
Note :: Note(istream &in)
{
_location = INSTAFF;
// Read the object data from the stream
in.read((char *) &_X, sizeof(_X));
in.read((char *) &_Y, sizeof(_Y));
in.read((char *) &_duration, sizeof(_duration));
}
Note :: Note(void far *&clipboard)
{
int far *&iclip = (int far *) clipboard;
_location = INSTAFF;
// Read the object data from the clipboard entry
_X = *iclip++;
_Y = *iclip++;
_duration = *iclip++;
}
void Note :: Draw(HDC hDC)
{
// Draw the staff extension lines if necessary
if (_Y < 0)
for (int y = -6; y >= _Y; y -= 6) {
MoveTo(hDC, _X+staffX-5, staffY+y);
LineTo(hDC, _X+staffX+6, staffY+y);
}
if (_Y > 24)
for (int y = 30; y <= _Y; y += 6) {
MoveTo(hDC, _X+staffX-5, staffY+y);
LineTo(hDC, _X+staffX+6, staffY+y);
}
// Load the appropriate bitmap
HDC hBitmapDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap;
int yCenter;
switch (_duration) {
case FULLDURATION:
hBitmap = LoadBitmap(hInst, "B_FULLNOTE");
yCenter = 10;
break;
case HALFDURATION:
if (_Y > 12) {
hBitmap = LoadBitmap(hInst, "B_HALFNOTEUP");
yCenter = 15;
}
else
{
hBitmap = LoadBitmap(hInst, "B_HALFNOTE");
yCenter = 4;
}
break;
case QUARTERDURATION:
if (_Y > 12) {
hBitmap = LoadBitmap(hInst, "B_QUARTERNOTEUP");
yCenter = 15;
}
else
{
hBitmap = LoadBitmap(hInst, "B_QUARTERNOTE");
yCenter = 4;
}
break;
case EIGHTHDURATION:
if (_Y > 12) {
hBitmap = LoadBitmap(hInst, "B_EIGHTHNOTEUP");
yCenter = 15;
}
else
{
hBitmap = LoadBitmap(hInst, "B_EIGHTHNOTE");
yCenter = 4;
}
break;
case SIXTEENTHDURATION:
if (_Y > 12) {
hBitmap = LoadBitmap(hInst, "B_SIXTEENTHNOTEUP");
yCenter = 15;
}
else
{
hBitmap = LoadBitmap(hInst, "B_SIXTEENTHNOTE");
yCenter = 4;
}
break;
}
// Draw the bitmap
HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
BitBlt(hDC, _X+staffX-16, _Y+staffY-yCenter, 32, 20, hBitmapDC, 0, 0, SRCAND);
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);
DeleteObject(hBitmap);
}
void Note :: Format(int &X)
{
// No special actions required: just copy the X coordinate
_X = X;
}
void Note :: MIDIPlay(ostream &out, int part)
{
// Write a Note On event in the temporary file
// with the correct frequency and duration
static const noteNumber[7] = {0, 2, 4, 5, 7, 9, 11};
out.put(0x90+part);
int octave = (30-_Y)/21;
int freq = (30-21*octave-_Y)/3;
out.write((char *) &_duration, sizeof(int));
out.put(12*(octave+4)+noteNumber[freq]);
out.put(0x40);
}
void Note :: printOn(ostream &out) const
{
// Write the object type ID (O_NOTE) and data to the stream
out.put(O_NOTE);
out.write((char *) &_X, sizeof(_X));
out.write((char *) &_Y, sizeof(_Y));
out.write((char *) &_duration, sizeof(_duration));
}
void Note :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_NOTE) and data to the clipboard entry
*bclip++ = O_NOTE;
*iclip++ = _X;
*iclip++ = _Y;
*iclip++ = _duration;
}
// **********************************************
// Definitions of the Pause class member functions
Pause :: Pause(int X, int duration)
{
// Copy the given parameters to the object variables
_location = INSTAFF;
_X = X;
_duration = duration;
}
Pause :: Pause(istream &in)
{
_location = INSTAFF;
// Read the object data from the stream
in.read((char *) &_X, sizeof(_X));
in.read((char *) &_duration, sizeof(_duration));
}
Pause :: Pause(void far *&clipboard)
{
int far *&iclip = (int far *) clipboard;
_location = INSTAFF;
// Read the object data from the clipboard entry
_X = *iclip++;
_duration = *iclip++;
}
void Pause :: Draw(HDC hDC)
{
// Draw the pause bitmap according to duration
switch (_duration) {
case FULLDURATION:
Rectangle(hDC, _X+staffX-5, staffY+7, _X+staffX+5, staffY+9);
break;
case HALFDURATION:
Rectangle(hDC, _X+staffX-5, staffY+10, _X+staffX+5, staffY+12);
break;
default:
HDC hBitmapDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap;
switch (_duration) {
case QUARTERDURATION:
hBitmap = LoadBitmap(hInst, "B_QUARTERPAUSE");
break;
case EIGHTHDURATION:
hBitmap = LoadBitmap(hInst, "B_EIGHTHPAUSE");
break;
case SIXTEENTHDURATION:
hBitmap = LoadBitmap(hInst, "B_SIXTEENTHPAUSE");
break;
}
HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
BitBlt(hDC, _X+staffX-16, staffY+2, 32, 20, hBitmapDC, 0, 0, SRCAND);
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);
DeleteObject(hBitmap);
break;
}
}
void Pause :: Format(int &X)
{
// No special actions required: just copy the X coordinate
_X = X;
}
void Pause :: MIDIPlay(ostream &out, int part)
{
// Put a Note Off event with the correct duration in the temporary file
out.put(0x80+part);
out.write((char *) &_duration, sizeof(int));
}
void Pause :: printOn(ostream &out) const
{
// Write the object type ID (O_PAUSE) and data to the stream
out.put(O_PAUSE);
out.write((char *) &_X, sizeof(_X));
out.write((char *) &_duration, sizeof(_duration));
}
void Pause :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_PAUSE) and data to the clipboard entry
*bclip++ = O_PAUSE;
*iclip++ = _X;
*iclip++ = _duration;
}
// **********************************************
// Definitions of the Key class member functions
Key :: Key(int, int type)
{
// Copy the given parameters to the object variables
_location = INSTAFF | ONEPERSTAFF;
_X = LOCATION;
_type = type;
}
Key :: Key(istream &in)
{
_location = INSTAFF | ONEPERSTAFF;
_X = LOCATION;
// Read the object data from the stream
in.read((char *) &_type, sizeof(_type));
}
Key :: Key(void far *&clipboard)
{
int far *&iclip = (int far *) clipboard;
_location = INSTAFF | ONEPERSTAFF;
_X = LOCATION;
// Read the object data from the clipboard entry
_type = *iclip++;
}
void Key :: Draw(HDC hDC)
{
HDC hBitmapDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap;
// Load the appropriate bitmap
switch (_type) {
case KEYSOL:
hBitmap = LoadBitmap(hInst, "B_KEYSOL");
break;
case KEYFA:
hBitmap = LoadBitmap(hInst, "B_KEYFA");
break;
}
// Draw the bitmap
HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
BitBlt(hDC, _X+staffX-16, staffY+4, 32, 20, hBitmapDC,
0, 0, SRCAND);
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);
DeleteObject(hBitmap);
}
void Key :: Format(int &)
{
// Keys cannot be formatted
}
void Key :: printOn(ostream &out) const
{
// Write the object type ID (O_KEY) and data to the stream
out.put(O_KEY);
out.write((char *) &_type, sizeof(_type));
}
void Key :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_KEY) to the clipboard entry
*bclip++ = O_KEY;
*iclip++ = _type;
}
// **********************************************
// Definitions of the Beat class member functions
Beat :: Beat(int X, int type)
{
// Copy the given parameters to the object variables
_location = COMMONMULTIPLE;
_X = X;
_type = type;
}
Beat :: Beat(istream &in)
{
_location = COMMONMULTIPLE;
// Read the object data from the stream
in.read((char *) &_X, sizeof(_X));
in.read((char *) &_type, sizeof(_type));
}
Beat :: Beat(void far *&clipboard)
{
int far *&iclip = (int far *) clipboard;
_location = COMMONMULTIPLE;
// Read the object data from the clipboard entry
_X = *iclip++;
_type = *iclip++;
}
void Beat :: Draw(HDC hDC)
{
HDC hBitmapDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap;
// Load the appropriate bitmap
switch (_type) {
case BEATC:
hBitmap = LoadBitmap(hInst, "B_BEATC");
break;
case BEATCBAR:
hBitmap = LoadBitmap(hInst, "B_BEATCBAR");
break;
case BEAT28:
hBitmap = LoadBitmap(hInst, "B_BEAT28");
break;
case BEAT24:
hBitmap = LoadBitmap(hInst, "B_BEAT24");
break;
case BEAT38:
hBitmap = LoadBitmap(hInst, "B_BEAT38");
break;
case BEAT34:
hBitmap = LoadBitmap(hInst, "B_BEAT34");
break;
case BEAT48:
hBitmap = LoadBitmap(hInst, "B_BEAT48");
break;
case BEAT44:
hBitmap = LoadBitmap(hInst, "B_BEAT44");
break;
case BEAT68:
hBitmap = LoadBitmap(hInst, "B_BEAT68");
break;
}
// Draw the bitmap
HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
BitBlt(hDC, _X+staffX-16, staffY+4, 32, 20, hBitmapDC,
0, 0, SRCAND);
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);
DeleteObject(hBitmap);
}
void Beat :: Format(int &X)
{
// No special actions required: just copy the X coordinate
_X = X;
}
void Beat :: printOn(ostream &out) const
{
// Write the object type ID (O_BEAT) and data to the stream
out.put(O_BEAT);
out.write((char *) &_X, sizeof(_X));
out.write((char *) &_type, sizeof(_type));
}
void Beat :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_BEAT) and data to the clipboard entry
*bclip++ = O_BEAT;
*iclip++ = _X;
*iclip++ = _type;
}
// **********************************************
// Definitions of the Bar class member functions
Bar :: Bar(int X, int type)
{
// Choose the _location attribute value according to bar type
switch (_type = type) {
case STARTBAR:
_location = COMMONMULTIPLE | ONEPERSTAFF;
_X = 0;
break;
case ENDBAR:
_location = COMMONMULTIPLE | ONEPERSTAFF;
_X = melody.GetStaffWidth();
break;
default:
_location = COMMONMULTIPLE;
_X = X;
break;
}
}
Bar :: Bar(istream &in)
{
_location = COMMONMULTIPLE;
// Read the object data from the stream
in.read((char *) &_X, sizeof(_X));
in.read((char *) &_type, sizeof(_type));
// Decide about the object _location attribute value according to type
if (_type == STARTBAR || _type == ENDBAR)
_location |= ONEPERSTAFF;
}
Bar :: Bar(void far *&clipboard)
{
int far *&iclip = (int far *) clipboard;
_location = COMMONMULTIPLE;
// Read the object data from the clipboard entry
_X = *iclip++;
_type = *iclip++;
// Decide about the _location attribute value according to type
if (_type == STARTBAR || _type == ENDBAR)
_location |= ONEPERSTAFF;
}
void Bar :: Draw(HDC hDC)
{
HBRUSH hOldBrush = SelectObject(hDC, GetStockObject(BLACK_BRUSH));
int Yfrom, Yto;
// Calculate the bar height limits
Yfrom = staffY;
switch (staffLoc) {
case SINGLESTAFF:
case LASTSTAFF:
Yto = staffY+24;
break;
case FIRSTSTAFF:
case MIDSTAFF:
Yto = staffY+currStaffHeight;
break;
}
// Draw the appropriate bar pattern
switch (_type) {
case BAR:
MoveTo(hDC, _X+staffX, Yfrom);
LineTo(hDC, _X+staffX, Yto);
break;
case DOUBLEBAR:
MoveTo(hDC, _X+staffX-2, Yfrom);
LineTo(hDC, _X+staffX-2, Yto);
MoveTo(hDC, _X+staffX+2, Yfrom);
LineTo(hDC, _X+staffX+2, Yto);
break;
case STARTBAR:
Rectangle(hDC, _X+staffX, Yfrom, _X+staffX+4, Yto);
MoveTo(hDC, _X+staffX+6, Yfrom);
LineTo(hDC, _X+staffX+6, Yto);
break;
case ENDBAR:
Rectangle(hDC, _X+staffX-3, Yfrom, _X+staffX+1, Yto);
MoveTo(hDC, _X+staffX-6, Yfrom);
LineTo(hDC, _X+staffX-6, Yto);
break;
}
SelectObject(hDC, hOldBrush);
}
void Bar :: Format(int &X)
{
// Bar can be moved unless it is fixed at the start or end of the staff
if (_type != STARTBAR && _type != ENDBAR)
_X = X;
}
void Bar :: printOn(ostream &out) const
{
// Write the object type ID (O_BAR) and data to the stream
out.put(O_BAR);
out.write((char *) &_X, sizeof(_X));
out.write((char *) &_type, sizeof(_type));
}
void Bar :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_BAR) and data to the clipboard entry
*bclip++ = O_BAR;
*iclip++ = _X;
*iclip++ = _type;
}
// **********************************************
// Definitions of the Loudness class member functions
Loudness :: Loudness(int X, int loudness)
{
// Copy the given parameters to the object variables
_location = BELOWMULTIPLE;
_X = X;
_loudness = loudness;
}
Loudness :: Loudness(istream &in)
{
_location = BELOWMULTIPLE;
// Read the object data from the stream
in.read((char *) &_X, sizeof(_X));
in.read((char *) &_loudness, sizeof(_loudness));
}
Loudness :: Loudness(void far *&clipboard)
{
int far *&iclip = (int far *) clipboard;
_location = BELOWMULTIPLE;
// Read the object data from the clipboard entry
_X = *iclip++;
_loudness = *iclip++;
}
void Loudness :: Draw(HDC hDC)
{
HDC hBitmapDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap;
// Load the appropriate bitmap
switch (_loudness) {
case FORTE:
hBitmap = LoadBitmap(hInst, "B_FORTE");
break;
case FORTISSIMO:
hBitmap = LoadBitmap(hInst, "B_FORTISSIMO");
break;
case PIANO:
hBitmap = LoadBitmap(hInst, "B_PIANO");
break;
case PIANISSIMO:
hBitmap = LoadBitmap(hInst, "B_PIANISSIMO");
break;
}
// Draw the bitmap
HBITMAP hOldBitmap = SelectObject(hBitmapDC, hBitmap);
BitBlt(hDC, _X+staffX-16, staffY+currStaffHeight/2-8, 32, 20, hBitmapDC,
0, 0, SRCAND);
SelectObject(hBitmapDC, hOldBitmap);
DeleteDC(hBitmapDC);
DeleteObject(hBitmap);
}
void Loudness :: Format(int &X)
{
// No special actions required: just copy the X coordinate
_X = X;
}
void Loudness :: printOn(ostream &out) const
{
// Write the object type ID (O_LOUDNESS) and data to the stream
out.put(O_LOUDNESS);
out.write((char *) &_X, sizeof(_X));
out.write((char *) &_loudness, sizeof(_loudness));
}
void Loudness :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_LOUDNESS) and data to the clipboard entry
*bclip++ = O_LOUDNESS;
*iclip++ = _X;
*iclip++ = _loudness;
}
// **********************************************
// Definitions of the Crescendo class member functions
Crescendo :: Crescendo(int Xleft, int Xright, int direction)
{
// Copy the given parameters to the object variables
_location = BELOWMULTIPLE;
_Xleft = Xleft;
_Xright = Xright;
_direction = direction;
}
Crescendo :: Crescendo(istream &in)
{
_location = BELOWMULTIPLE;
// Read the object data from the stream
in.read((char *) &_Xleft, sizeof(_Xleft));
in.read((char *) &_Xright, sizeof(_Xright));
in.read((char *) &_direction, sizeof(_direction));
}
Crescendo :: Crescendo(void far *&clipboard)
{
int far *&iclip = (int far *) clipboard;
_location = BELOWMULTIPLE;
// Read the object data from the clipboard entry
_Xleft = *iclip++;
_Xright = *iclip++;
_direction = *iclip++;
}
void Crescendo :: Draw(HDC hDC)
{
// Draw the pair of lines according to direction
MoveTo(hDC, staffX+((_direction == CRESCENDO) ? _Xright : _Xleft),
staffY+currStaffHeight/2+4);
LineTo(hDC, staffX+((_direction == CRESCENDO) ? _Xleft : _Xright),
staffY+currStaffHeight/2+8);
LineTo(hDC, staffX+((_direction == CRESCENDO) ? _Xright : _Xleft),
staffY+currStaffHeight/2+12);
}
void Crescendo :: printOn(ostream &out) const
{
// Write the object type ID (O_CRESCENDO) and data to the stream
out.put(O_CRESCENDO);
out.write((char *) &_Xleft, sizeof(_Xleft));
out.write((char *) &_Xright, sizeof(_Xright));
out.write((char *) &_direction, sizeof(_direction));
}
void Crescendo :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_CRESCENDO) and data to the clipboard entry
*bclip++ = O_CRESCENDO;
*iclip++ = _Xleft;
*iclip++ = _Xright;
*iclip++ = _direction;
}
// **********************************************
// Definitions of the Text class member functions
Text :: Text(int X, int Y, char *string)
{
// Copy the given parameters to the object variables
_location = INSTAFF;
_X = X;
_Y = (Y > 12) ? 30 : -21;
strcpy(_text, string);
}
Text :: Text(istream &in)
{
_location = INSTAFF;
// Read the object data from the stream
in.read((char *) &_X, sizeof(_X));
in.read((char *) &_Y, sizeof(_Y));
in.get(_text, MAXTEXT+1, 0);
in.get();
}
Text :: Text(void far *&clipboard)
{
_location = INSTAFF;
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Read the object data from the clipboard entry
_X = *iclip++;
_Y = *iclip++;
_fstrcpy(_text, bclip);
bclip += _fstrlen(bclip)+1;
}
void Text :: Draw(HDC hDC)
{
// Put the text in a transparent fashion (i.e. not erasing the background)
SetBkMode(hDC, TRANSPARENT);
TextOut(hDC, _X+staffX, _Y+staffY, _text, strlen(_text));
}
void Text :: Format(int &X)
{
// No special actions required: just copy the X coordinate
_X = X;
}
void Text :: printOn(ostream &out) const
{
// Write the object type ID (O_TEXT) and data to the stream
out.put(O_TEXT);
out.write((char *) &_X, sizeof(_X));
out.write((char *) &_Y, sizeof(_Y));
out.write(_text, strlen(_text)+1);
}
void Text :: clipOn(void far *&clipboard) const
{
char far *&bclip = (char far *) clipboard;
int far *&iclip = (int far *) clipboard;
// Write the object type ID (O_TEXT) and data to the clipboard entry
*bclip++ = O_TEXT;
*iclip++ = _X;
*iclip++ = _Y;
_fstrcpy(bclip, _text);
bclip += strlen(_text)+1;
}