home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
m
/
muzsrc1.zip
/
FORMAT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-22
|
7KB
|
174 lines
// **********************************************
// File: FORMAT.CPP
// Musical text formatting functions
#include "muzika.h"
#include <alloc.h>
#include <values.h>
// **********************************************
// FindMinDuration finds the minimum in a list and
// returns its index. This function is used to find
// the minimum duration of the next object among several staves.
int FindMinDuration(int *duration, int multiplicity)
{
int min = MAXINT, minIndex;
int *p = duration;
while (multiplicity--) {
if (min > *p) {
min = *p;
minIndex = p-duration;
}
++p;
}
return minIndex;
}
// **********************************************
// FormatMultipleStaff reformats a multiple staff.
// This function is called once for every multiple staff in the part.
void FormatMultipleStaff(int baseStaff)
{
// Create a few lists for use in the algorithm
Part &p = *((Part *) &melody.part[displayedPart]);
int *duration = (int *) malloc(p.multiplicity()*sizeof(int));
int *index = (int *) malloc(p.multiplicity()*sizeof(int));
BOOL *atCommon = (int *) malloc(p.multiplicity()*sizeof(BOOL));
BOOL *staffEnd = (int *) malloc(p.multiplicity()*sizeof(BOOL));
memset(duration, 0, p.multiplicity()*sizeof(int));
memset(index, 0, p.multiplicity()*sizeof(int));
memset(atCommon, 0, p.multiplicity()*sizeof(BOOL));
memset(staffEnd, 0, p.multiplicity()*sizeof(BOOL));
int X = 0;
BOOL multipleEnd, multipleReached = FALSE;
// Create unions of the continuousObject lists sorted by Xleft and Xright
IndexedList sortedByLeft, sortedByRight;
int leftIndex, rightIndex;
for (int staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex) {
Staff &s = *((Staff *) &p.staff[baseStaff+staffIndex]);
for (int orgIndex = 0; orgIndex < s.continuousObject.number(); ++orgIndex) {
for (leftIndex = 0;
leftIndex < sortedByLeft.number() &&
((ContinuousObject *) &sortedByLeft[leftIndex])->Xleft() <=
((ContinuousObject *) &s.continuousObject[orgIndex])->Xleft();
++leftIndex);
sortedByLeft.insertAt(s.continuousObject[orgIndex], leftIndex);
for (rightIndex = 0;
rightIndex < sortedByRight.number() &&
((ContinuousObject *) &sortedByRight[rightIndex])->Xright() <=
((ContinuousObject *) &s.continuousObject[orgIndex])->Xright();
++rightIndex);
sortedByRight.insertAt(s.continuousObject[orgIndex], rightIndex);
}
}
// Loop as long as the end has not been reached on all staves
do {
// Find the staff with the minimum duration of the next object
int minIndex = FindMinDuration(duration, p.multiplicity());
int minDuration = duration[minIndex];
int maxWidth = 0;
multipleEnd = TRUE;
// Subtract the minimum duration from all staves;
// place the next object on the ones which reach 0 as a result
for (staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex) {
Staff &s = *((Staff *) &p.staff[baseStaff+staffIndex]);
if (atCommon[staffIndex] || !(duration[staffIndex] -= minDuration)) {
// The next object duration has reached 0:
// place the next object in the staff
int currX = ((PointObject *) &s.pointObject[index[staffIndex]])->X();
while (!(staffEnd[staffIndex] =
index[staffIndex] == s.pointObject.number())) {
PointObject &obj =
*((PointObject *) &s.pointObject[index[staffIndex]]);
if (obj.X() == currX) {
if ((obj.location() & ~ONEPERSTAFF) == COMMONMULTIPLE) {
// The object has a COMMONMULTIPLE location attribute:
// mark the place and wait for other staves to reach
// this object too
atCommon[staffIndex] = !multipleReached;
duration[staffIndex] = multipleReached ? 0 : MAXINT;
if (!multipleReached)
break;
}
// Reinitialize the next object duration
if (duration[staffIndex] < obj.Duration())
duration[staffIndex] = obj.Duration();
// Call the object's Format virtual function,
// in case the object wants to do something during formatting
obj.Format(X);
if (maxWidth < obj.Width())
maxWidth = obj.Width();
++index[staffIndex];
// Adjust the left and right coordinates
// of any continuous objects that have been reached
// while reformatting the point objects
while (leftIndex < sortedByLeft.number() &&
((ContinuousObject *)
&sortedByLeft[leftIndex])->Xleft() <= currX)
((ContinuousObject *)
&sortedByLeft[leftIndex++])->FormatLeft(X);
while (rightIndex < sortedByRight.number() &&
((ContinuousObject *)
&sortedByRight[rightIndex])->Xright() <= currX)
((ContinuousObject *)
&sortedByRight[rightIndex++])->FormatRight(X);
}
else break;
}
}
// See if the end has been reached on all staves
multipleEnd = multipleEnd && staffEnd[staffIndex];
}
// See if an object with a COMMONMULTIPLE location attribute
// has been reached on all staves
multipleReached = TRUE;
for (staffIndex = 0; staffIndex < p.multiplicity(); ++staffIndex)
multipleReached = multipleReached && atCommon[staffIndex];
X += maxWidth;
} while (!multipleEnd);
// Free the continuous object list copies
for (int i = sortedByLeft.number()-1; i >= 0; --i) {
sortedByLeft.detachAt(i);
sortedByRight.detachAt(i);
}
// Free all temporary lists on the heap
free(staffEnd);
free(atCommon);
free(index);
free(duration);
}
// **********************************************
// FormatEntirePart reformats the displayed part
// by calling FormatMultipleStaff once per every multiple staff
// in the part.
void FormatEntirePart()
{
Part &p = *((Part *) &melody.part[displayedPart]);
// Call FormatMultipleStaff for every multiple staff in the part
for (int index = 0; index < p.staff.number(); index += p.multiplicity())
FormatMultipleStaff(index);
// Mark the melody as modified and refresh screen
melodyModified = TRUE;
InvalidateRect(hEditWnd, NULL, TRUE);
}