~s-cecilio/lenmus/v5.3

« back to all changes in this revision

Viewing changes to src/score/Score.cpp

  • Committer: cecilios
  • Date: 2006-03-05 11:33:10 UTC
  • Revision ID: svn-v4:2587a929-2f0e-0410-ae78-fe6f687d5efe:trunk:2
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// RCS-ID: $Id: Score.cpp,v 1.3 2006/02/23 19:23:54 cecilios Exp $
 
2
//--------------------------------------------------------------------------------------
 
3
//    LenMus Phonascus: The teacher of music
 
4
//    Copyright (c) 2002-2006 Cecilio Salmeron
 
5
//
 
6
//    This program is free software; you can redistribute it and/or modify it under the 
 
7
//    terms of the GNU General Public License as published by the Free Software Foundation;
 
8
//    either version 2 of the License, or (at your option) any later version.
 
9
//
 
10
//    This program is distributed in the hope that it will be useful, but WITHOUT ANY 
 
11
//    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
 
12
//    PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 
13
//
 
14
//    You should have received a copy of the GNU General Public License along with this 
 
15
//    program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, 
 
16
//    Fifth Floor, Boston, MA  02110-1301, USA.
 
17
//
 
18
//    For any comment, suggestion or feature request, please contact the manager of 
 
19
//    the project at cecilios@users.sourceforge.net
 
20
//
 
21
//-------------------------------------------------------------------------------------
 
22
/*! @file Score.cpp
 
23
    @brief Implementation file for class lmScore
 
24
    @ingroup score_kernel
 
25
*/
 
26
//--------------------------------------------------------------------------------------------------
 
27
/*! @class lmScore
 
28
    @ingroup score_kernel
 
29
 
 
30
    A score is a collection of instruments (\<parts\> in MusicXML).
 
31
    An instrument is, normally, one VStaff, but more VStaves are posible (for what?)
 
32
    And an VStaff is a collection of StaffObjs.
 
33
 
 
34
*/
 
35
//--------------------------------------------------------------------------------------------------
 
36
 
 
37
#ifdef __GNUG__
 
38
// #pragma implementation
 
39
#endif
 
40
 
 
41
// For compilers that support precompilation, includes "wx/wx.h".
 
42
#include "wx/wxprec.h"
 
43
 
 
44
#ifdef __BORLANDC__
 
45
#pragma hdrstop
 
46
#endif
 
47
 
 
48
#ifndef WX_PRECOMP
 
49
#include "wx/wx.h"
 
50
#endif
 
51
 
 
52
#include "wx/debug.h"
 
53
#include "wx/list.h"
 
54
#include "Score.h"
 
55
#include "../app/global.h"
 
56
 
 
57
// global unique variables used during score building
 
58
lmNoteRest*    g_pLastNoteRest;
 
59
lmBeam*        g_pCurBeam;            // lmBeam object that is being built ot NULL if none in process. See lmNote constructor
 
60
 
 
61
// access to colors
 
62
#include "../globals/Colors.h"
 
63
extern lmColors* g_pColors;
 
64
 
 
65
//---------------------------------------------------------------------------------------
 
66
// lmScore constructors and destructor
 
67
//---------------------------------------------------------------------------------------
 
68
 
 
69
lmScore::lmScore()
 
70
{
 
71
    //Set up an empty score, that is, without any lmInstrument.
 
72
    
 
73
    m_pTitle = (lmText*)NULL;        //no title
 
74
    m_pSubtitle = (lmText*)NULL;    //no subtitle
 
75
 
 
76
    //create the renderer object
 
77
    m_pFormatter = new lmFormatter3();
 
78
    m_pFormatter->SetScore(this);
 
79
 
 
80
    //initializations
 
81
    m_pSoundMngr = (lmSoundManager*)NULL;
 
82
 
 
83
    //! @todo fill this not with constants
 
84
    m_nSystemsDistance = 20000;            // 2 cm = 20 mm = 20,000 microns
 
85
    m_nTopSystemDistance = 20000;        // 2 cm = 20 mm = 20,000 microns
 
86
    m_nSystemsLeftMargin = 0;
 
87
    m_nSystemsRightMargin = 0;
 
88
 
 
89
}
 
90
 
 
91
lmScore::~lmScore()
 
92
{
 
93
    //wxLogMessage(_T("[lmScore::~lmScore] Deleting lmScore object"));
 
94
    if (m_pFormatter) delete m_pFormatter;
 
95
    m_cInstruments.DeleteContents(true);
 
96
    m_cInstruments.Clear();
 
97
 
 
98
    m_cGlobalStaffobjs.DeleteContents(true);
 
99
    m_cGlobalStaffobjs.Clear();
 
100
 
 
101
    if (m_pSoundMngr) {
 
102
        m_pSoundMngr->DeleteEventsTable();
 
103
        delete m_pSoundMngr;
 
104
    }
 
105
 
 
106
    m_cHighlighted.DeleteContents(false);    //Staffobjs must not be deleted, only the list
 
107
    m_cHighlighted.Clear();
 
108
 
 
109
    if (m_pTitle) delete m_pTitle;
 
110
    if (m_pSubtitle) delete m_pSubtitle;
 
111
 
 
112
}
 
113
 
 
114
//---------------------------------------------------------------------------------------
 
115
// score object methods
 
116
//---------------------------------------------------------------------------------------
 
117
 
 
118
void lmScore::SetTitle(wxString title)
 
119
{
 
120
    if (!m_pTitle) {
 
121
        m_pTitle = new lmText(this, title, 0, 0, false, false, _T("Garamond"), 14, true, false );
 
122
        IncludeInGlobalList(m_pTitle);
 
123
    }
 
124
    else {
 
125
        m_pTitle->SetText(title);
 
126
    }
 
127
}
 
128
 
 
129
void lmScore::SetSubtitle(wxString subtitle)
 
130
{
 
131
    if (!m_pSubtitle) {
 
132
        m_pSubtitle = new lmText(this, subtitle, 0, 0, false, false, _T("Garamond"), 11, false, true );
 
133
        IncludeInGlobalList(m_pSubtitle);
 
134
    }
 
135
    else {
 
136
        m_pSubtitle->SetText(subtitle);
 
137
    }
 
138
}
 
139
 
 
140
wxInt32 lmScore::GetNumMeasures()
 
141
{
 
142
    //! @limit it is being assumed that all instruments and staves have the same number of bars
 
143
    InstrumentsList::Node *node = m_cInstruments.GetFirst();
 
144
    lmInstrument *pInstr = node->GetData();
 
145
    lmVStaff *pStaff = pInstr->GetVStaff(1);
 
146
    return(pStaff->GetNumMeasures());
 
147
}
 
148
 
 
149
lmInstrument* lmScore::AddInstrument(wxInt32 nVStaves, wxInt32 nMIDIChannel, wxInt32 nMIDIInstr)
 
150
{
 
151
    //add an lmInstrument with nVStaves (1..m) empty VStaves.
 
152
    //nMIDIChannel is the MIDI channel to use for playing this instrument
 
153
    lmInstrument* pInstr = new lmInstrument(this, nVStaves, nMIDIChannel, nMIDIInstr);
 
154
    m_cInstruments.Append(pInstr);
 
155
    return pInstr;
 
156
    
 
157
}
 
158
 
 
159
//returns lmVStaff number nVStaff (1..n), of lmInstrument nInstr (1..m)
 
160
lmVStaff* lmScore::GetVStaff(wxInt32 nInstr, wxInt32 nVStaff)
 
161
{
 
162
    wxInt32 i;
 
163
    InstrumentsList::Node *node;
 
164
    lmInstrument *pInstr;
 
165
    //iterate over the list to locate lmInstrument nInstr
 
166
    for (i=1, node = m_cInstruments.GetFirst(); 
 
167
        node && i < nInstr; node = node->GetNext(), i++ ) {}
 
168
//    wxASSERT_MSG{pInstr != 0, _T("No existe el Instrumento num. nInstr"));
 
169
    pInstr = node->GetData();
 
170
    return(pInstr->GetVStaff(nVStaff));
 
171
}
 
172
 
 
173
lmInstrument* lmScore::XML_FindInstrument(wxString sId)
 
174
{
 
175
    // iterate over instrument list to find the one with id == sId
 
176
    wxInstrumentsListNode *node;
 
177
    lmInstrument* pInstr = (lmInstrument*)NULL;
 
178
    for (node = m_cInstruments.GetFirst(); node; node = node->GetNext()) {
 
179
        pInstr = (lmInstrument*)node->GetData();
 
180
        if (pInstr->XML_GetId() == sId) break;
 
181
    }
 
182
    return pInstr;
 
183
}
 
184
 
 
185
void lmScore::Draw(lmPaper *pPaper)
 
186
{
 
187
//            Optional fMetodoJustificado As Boolean = True, _
 
188
//            Optional nTipoEspaciado As ESpacingMethod = esm_PropConstantShortNote, _
 
189
//            Optional fJustificada As Boolean = True, _
 
190
//            Optional fTruncarUltimoSistema As Boolean = False, _
 
191
//            Optional rFactorAjuste As Single = 1#)
 
192
//
 
193
 
 
194
 
 
195
    ////DEBUG: draw green lines to show page borders
 
196
    //wxDC* pDC = pPaper->GetDC();
 
197
    //wxASSERT(pDC);
 
198
    //lmMicrons yTop = pPaper->GetCursorY();
 
199
    //lmMicrons xLeft = pPaper->GetLeftMarginXPos();
 
200
    //lmMicrons xRight = pPaper->GetRightMarginXPos();
 
201
    //pDC->SetPen(*wxGREEN_PEN);
 
202
    //pDC->DrawLine(xLeft, yTop, xRight, yTop);    //top horizontal
 
203
    //pDC->DrawLine(xLeft, yTop, xLeft, (pPaper->GetPaperSize()).GetHeight());    //left vertical
 
204
    //pDC->DrawLine(xRight, yTop, xRight, (pPaper->GetPaperSize()).GetHeight());    //right vertical
 
205
    ////End DEBUG --------------------------------------------
 
206
 
 
207
    //WriteTitles(DO_MEASURE, pPaper);
 
208
    //WriteTitles(DO_DRAW, pPaper);
 
209
    m_pFormatter->RenderScore(pPaper);
 
210
 
 
211
}
 
212
 
 
213
void lmScore::WriteTitles(bool fMeasuring, lmPaper *pPaper)
 
214
{
 
215
    long nWidth, nHeight;
 
216
    lmMicrons xPos=0;
 
217
 
 
218
    if (fMeasuring) {
 
219
        // Measurement phase ---------------------------------------------------
 
220
 
 
221
        m_nHeadersHeight = 0;
 
222
 
 
223
        // measure Title if exits
 
224
        if (m_pTitle) {
 
225
            // center Title
 
226
            if (!m_pTitle->IsFixed()) {
 
227
                m_pTitle->Draw(DO_MEASURE, pPaper);
 
228
                nWidth = m_pTitle->GetSelRect().width;
 
229
                nHeight = m_pTitle->GetSelRect().height;
 
230
                xPos = (pPaper->GetRightMarginXPos() - pPaper->GetLeftMarginXPos() - nWidth)/2;
 
231
                pPaper->SetCursorX(pPaper->GetLeftMarginXPos() + xPos);
 
232
            }
 
233
            m_pTitle->Draw(DO_MEASURE, pPaper);
 
234
            m_pTitle->SetFixed(true);
 
235
            nWidth = m_pTitle->GetSelRect().width;
 
236
            nHeight = m_pTitle->GetSelRect().height;
 
237
 
 
238
            // advance paper and update headers total height
 
239
            pPaper->IncrementCursorY(nHeight);
 
240
            m_nHeadersHeight += nHeight;
 
241
        }
 
242
 
 
243
        // measure Subtitle if exits
 
244
        if (m_pSubtitle) {
 
245
            // center subtitle
 
246
            if (!m_pSubtitle->IsFixed()) {
 
247
                m_pSubtitle->Draw(DO_MEASURE, pPaper);
 
248
                nWidth = m_pSubtitle->GetSelRect().width;
 
249
                nHeight = m_pSubtitle->GetSelRect().height;
 
250
                xPos = (pPaper->GetRightMarginXPos() - pPaper->GetLeftMarginXPos() - nWidth)/2;
 
251
                pPaper->SetCursorX(pPaper->GetLeftMarginXPos() + xPos);
 
252
            }
 
253
 
 
254
            //render subtitle
 
255
            m_pSubtitle->Draw(DO_MEASURE, pPaper);
 
256
            m_pSubtitle->SetFixed(true);
 
257
            nWidth = m_pSubtitle->GetSelRect().width;
 
258
            nHeight = m_pSubtitle->GetSelRect().height;
 
259
 
 
260
            //update headers total height
 
261
            m_nHeadersHeight += nHeight;
 
262
        }
 
263
 
 
264
    }
 
265
 
 
266
    else {
 
267
        // Drawing phase ---------------------------------------------------
 
268
        if (m_pTitle) m_pTitle->Draw(DO_DRAW, pPaper);
 
269
        if (m_pSubtitle) m_pSubtitle->Draw(DO_DRAW, pPaper);
 
270
    }
 
271
 
 
272
}
 
273
 
 
274
void lmScore::IncludeInGlobalList(lmStaffObj* pSO)
 
275
{
 
276
    m_cGlobalStaffobjs.Append(pSO);
 
277
}
 
278
 
 
279
void lmScore::RemoveFromGlobalList(lmStaffObj* pSO)
 
280
{
 
281
    m_cGlobalStaffobjs.DeleteObject(pSO);
 
282
}
 
283
 
 
284
//=========================================================================================
 
285
// Methods for finding StaffObjs
 
286
//=========================================================================================
 
287
 
 
288
lmScoreObj* lmScore::FindSelectableObject(wxPoint& pt)
 
289
{
 
290
    wxInt32 iVStaff;
 
291
    lmInstrument *pInstr;
 
292
    lmVStaff *pStaff;
 
293
    InstrumentsList::Node *node;
 
294
    lmScoreObj* pScO;
 
295
 
 
296
    //Look up in the global StaffObjs list
 
297
    wxStaffObjsListNode* pNode;
 
298
    for(pNode = m_cGlobalStaffobjs.GetFirst(); pNode; pNode = pNode->GetNext()) {
 
299
        pScO = (lmScoreObj*)pNode->GetData();
 
300
        if (pScO->IsAtPoint(pt)) {
 
301
            return pScO;
 
302
        }
 
303
    }
 
304
 
 
305
    //Not found in global list. Look up in the VStaffs' lists
 
306
 
 
307
    //for each instrument
 
308
    for (node = m_cInstruments.GetFirst(); node; node=node->GetNext()) {
 
309
        pInstr = node->GetData();
 
310
        
 
311
        //for each lmVStaff
 
312
        for (iVStaff=1; iVStaff <= pInstr->GetNumStaves(); iVStaff++) {
 
313
            pStaff = pInstr->GetVStaff(iVStaff);
 
314
            
 
315
            //look for posible lmStaffObj and exit if any found
 
316
            pScO = pStaff->FindSelectableObject(pt);
 
317
            if (pScO) return(pScO);
 
318
        }
 
319
    }
 
320
    return (lmScoreObj *)NULL;    //none found
 
321
}
 
322
 
 
323
////Friend methods for lmFormatter object and for internal use
 
324
////=========================================================================================
 
325
 
 
326
lmInstrument* lmScore::GetFirstInstrument()
 
327
{
 
328
    m_pNode = m_cInstruments.GetFirst();
 
329
    return (m_pNode ? (lmInstrument *)m_pNode->GetData() : (lmInstrument *)m_pNode);
 
330
}
 
331
 
 
332
lmInstrument* lmScore::GetNextInstrument()
 
333
{
 
334
    wxASSERT(m_pNode);
 
335
    m_pNode = m_pNode->GetNext();
 
336
    return (m_pNode ? (lmInstrument *)m_pNode->GetData() : (lmInstrument *)m_pNode);
 
337
}
 
338
 
 
339
lmInstrument* lmScore::GetLastInstrument()
 
340
{
 
341
    wxASSERT(m_pNode);
 
342
    m_pNode = m_cInstruments.GetLast();
 
343
    return (m_pNode ? (lmInstrument *)m_pNode->GetData() : (lmInstrument *)m_pNode);
 
344
}
 
345
 
 
346
////Returns the lmInstrument number nInstr (1..n)
 
347
//Friend Property Get lmInstrument(nInstr As Long) As CInstrumento
 
348
//    Set lmInstrument = m_cInstruments.Item(nInstr)
 
349
//    
 
350
//}
 
351
//
 
352
////Returns the number of Instruments in the Score
 
353
//Friend Property Get InstrumentsCount() As Long
 
354
//    InstrumentsCount = m_cInstruments.Count
 
355
//    
 
356
//}
 
357
//
 
358
////== End of Friend methods for lmFormatter object ============================================
 
359
 
 
360
wxString lmScore::Dump()
 
361
{
 
362
    wxString sDump = _T("Global objects:\n");
 
363
 
 
364
    //loop to dump global StaffObjs
 
365
    lmStaffObj* pSO;
 
366
    wxStaffObjsListNode* pNode;
 
367
    for(pNode = m_cGlobalStaffobjs.GetFirst(); pNode; pNode = pNode->GetNext()) {
 
368
        pSO = (lmStaffObj*)pNode->GetData();
 
369
        sDump += pSO->Dump();
 
370
    }
 
371
 
 
372
    //loop to dump all instruments
 
373
    sDump += _T("\nLocal objects:\n");
 
374
    lmInstrument *pInstr = GetFirstInstrument();
 
375
    for (int i=1; i<= (int)m_cInstruments.GetCount(); i++, pInstr = GetNextInstrument())
 
376
    {
 
377
        sDump += wxString::Format(_T("\nInstrument %d\n"), i );
 
378
        sDump += pInstr->Dump();
 
379
    }
 
380
    return sDump;
 
381
}
 
382
 
 
383
wxString lmScore::SourceLDP()
 
384
{
 
385
    wxString sSource = 
 
386
        wxString::Format(_T("Partitura\n   (Vers 1.3)\n   (NumInstrumentos %d)\n"),
 
387
                    m_cInstruments.GetCount() );
 
388
 
 
389
    //loop for each instrument
 
390
     lmInstrument *pInstr = GetFirstInstrument();
 
391
    for (int i=1; i<= (int)m_cInstruments.GetCount(); i++, pInstr = GetNextInstrument())
 
392
    {
 
393
        sSource += wxString::Format(_T("   (Instrumento %d\n"), i);
 
394
        sSource += pInstr->SourceLDP();
 
395
        sSource += _T("   )\n");
 
396
    }
 
397
    sSource += _T(")");
 
398
    return sSource;
 
399
}
 
400
 
 
401
wxString lmScore::SourceXML()
 
402
{
 
403
    wxString sSource = _T("TODO: lmScore XML Source code generation methods");
 
404
 
 
405
//    Dim i As Long, sFuente As String
 
406
//    
 
407
//    sFuente = "<?xml version=""1.0"" standalone=""no""?>" & sCrLf & _
 
408
//            "<!DOCTYPE score-partwise PUBLIC ""-//Recordare//DTD MusicXML 0.7 Partwise//EN"" " & _
 
409
//            """http://www.musicxml.org/dtds/partwise.dtd"">" & sCrLf & _
 
410
//            "<score-partwise>" & sCrLf & _
 
411
//            "  <part-list>" & sCrLf
 
412
////        <score-part id="P1">
 
413
////            <part-name>Voice</part-name>
 
414
////        </score-part>
 
415
//
 
416
////    sFuente = sFuente & "<Partitura" & sCrLf & "   (Vers 1.3)" & sCrLf & "   (NumInstrumentos " & _
 
417
////        m_cInstruments.Count & ")" & sCrLf
 
418
//    for (i = 1 To m_cInstruments.Count
 
419
//        sFuente = sFuente & "    <score-part id=""P" & i & """ >" & sCrLf
 
420
////        sFuente = sFuente & m_cInstruments.Item(i).FuenteXML
 
421
////        sFuente = sFuente & "   )" & sCrLf
 
422
//        sFuente = sFuente & "    </score-part>" & sCrLf
 
423
//    }    // i
 
424
//    sFuente = sFuente & "  </part-list>" & sCrLf
 
425
//    for (i = 1 To m_cInstruments.Count
 
426
//        sFuente = sFuente & "  <part id=""P" & i & """ >" & sCrLf
 
427
//        sFuente = sFuente & m_cInstruments.Item(i).FuenteXML
 
428
//        sFuente = sFuente & "  </part>" & sCrLf
 
429
//    }    // i
 
430
//    FuenteXML = sFuente & "</score-partwise>" & sCrLf
 
431
    return sSource;
 
432
        
 
433
}
 
434
 
 
435
////Toca el compas nCompas (1 .. n)
 
436
//void lmScore::PlayMeasure(nCompas As Long, fVisualTracking As Boolean, _
 
437
//                fRecuadrarCompas As Boolean, nPlayMode As EPlayMode)
 
438
//{
 
439
//
 
440
//    if (!fMIDIEnabled) return;
 
441
//    if (m_pSoundMngr Is Nothing) { ComputeMidiEvents
 
442
//
 
443
//    m_pSoundMngr->PlayMeasure nCompas, fVisualTracking, fRecuadrarCompas, nPlayMode
 
444
//
 
445
//}
 
446
 
 
447
void lmScore::Play(bool fVisualTracking, bool fMarcarCompasPrevio, EPlayMode nPlayMode, 
 
448
                 long nMM, wxWindow* pWindow)
 
449
{
 
450
    if (!m_pSoundMngr) {
 
451
        m_pSoundMngr = new lmSoundManager();
 
452
        ComputeMidiEvents();
 
453
    }
 
454
 
 
455
    m_pSoundMngr->Play(fVisualTracking, fMarcarCompasPrevio, nPlayMode, nMM, pWindow);
 
456
 
 
457
}
 
458
 
 
459
void lmScore::PlayMeasure(int nMeasure, bool fVisualTracking, EPlayMode nPlayMode,
 
460
                          long nMM, wxWindow* pWindow)
 
461
{
 
462
    if (!m_pSoundMngr) {
 
463
        m_pSoundMngr = new lmSoundManager();
 
464
        ComputeMidiEvents();
 
465
    }
 
466
 
 
467
    m_pSoundMngr->PlayMeasure(nMeasure, fVisualTracking, nPlayMode, nMM, pWindow);
 
468
}
 
469
 
 
470
void lmScore::Pause()
 
471
{
 
472
    if (!m_pSoundMngr) return;
 
473
    m_pSoundMngr->Pause();
 
474
 
 
475
}
 
476
 
 
477
void lmScore::Stop()
 
478
{
 
479
    if (!m_pSoundMngr) return;
 
480
    m_pSoundMngr->Stop();
 
481
 
 
482
}
 
483
 
 
484
void lmScore::WaitForTermination()
 
485
{
 
486
    if (!m_pSoundMngr) return;
 
487
    m_pSoundMngr->WaitForTermination();
 
488
 
 
489
}
 
490
 
 
491
void lmScore::ScoreHighlight(lmStaffObj* pSO, lmPaper* pPaper, EHighlightType nHighlightType)
 
492
{
 
493
    switch (nHighlightType) {
 
494
        case eVisualOn:
 
495
            m_cHighlighted.Append(pSO);
 
496
            pSO->Draw(DO_DRAW, pPaper, g_pColors->ScoreHighlight() );
 
497
            break;
 
498
 
 
499
        case eVisualOff:
 
500
            m_cHighlighted.DeleteObject(pSO);
 
501
            RemoveHighlight(pSO, pPaper);
 
502
            break;
 
503
 
 
504
        case eRemoveAllHighlight:
 
505
            //remove highlight from all staffobjs in m_cHighlighted list
 
506
            wxStaffObjsListNode* pNode;
 
507
            for(pNode = m_cHighlighted.GetFirst(); pNode; pNode = pNode->GetNext()) {
 
508
                RemoveHighlight( (lmStaffObj*)pNode->GetData(), pPaper );
 
509
            }
 
510
            //clear the list
 
511
            m_cHighlighted.DeleteContents(false);    //Staffobjs must not be deleted, only the list
 
512
            m_cHighlighted.Clear();
 
513
            break;
 
514
 
 
515
        default:
 
516
            wxASSERT(false);
 
517
    }
 
518
 
 
519
}
 
520
 
 
521
void lmScore::RemoveHighlight(lmStaffObj* pSO, lmPaper* pPaper)
 
522
{
 
523
    /*! @todo
 
524
        If we paint in black it remains a red aureole around
 
525
        the note. By painting it first in white the size of the aureole
 
526
        is smaller but still visible. A posible better solution is to
 
527
        modify Draw() method to accept an additional parameter: a flag
 
528
        to signal that XOR draw mode in RED followed by a normal
 
529
        draw in BLACK must be done.
 
530
    */
 
531
    pSO->Draw(DO_DRAW, pPaper, *wxWHITE);
 
532
    pSO->Draw(DO_DRAW, pPaper, g_pColors->ScoreNormal() );
 
533
}
 
534
 
 
535
void lmScore::ComputeMidiEvents()
 
536
{
 
537
    int nChannel, nInstr;        //MIDI info. for instrument in process
 
538
    lmSoundManager* pSM;            
 
539
    
 
540
    if (m_pSoundMngr)
 
541
        m_pSoundMngr->DeleteEventsTable();
 
542
    else
 
543
        m_pSoundMngr = new lmSoundManager();
 
544
 
 
545
    //Loop to generate Midi events for each instrument
 
546
    lmVStaff* pVStaff;
 
547
     lmInstrument *pInstr = GetFirstInstrument();
 
548
    for (int i=1; i<= (int)m_cInstruments.GetCount(); i++, pInstr = GetNextInstrument())
 
549
    {       
 
550
        nChannel = pInstr->GetMIDIChannel();
 
551
        nInstr = pInstr->GetMIDIInstrument();
 
552
 
 
553
       //for each lmVStaff
 
554
        for (int iVStaff=1; iVStaff <= pInstr->GetNumStaves(); iVStaff++) {
 
555
            pVStaff = pInstr->GetVStaff(iVStaff);
 
556
            pSM = pVStaff->ComputeMidiEvents(nChannel);
 
557
            m_pSoundMngr->Append(pSM);
 
558
            delete pSM;
 
559
        }
 
560
 
 
561
        //Add an event to program sound for this instrument
 
562
        m_pSoundMngr->StoreEvent(0, eSET_ProgInstr, nChannel, nInstr, 0, (lmStaffObj*)NULL, 0);
 
563
        
 
564
    }
 
565
    
 
566
    //End up Midi events table and sort it by time
 
567
    m_pSoundMngr->CloseTable();
 
568
    
 
569
}
 
570
 
 
571
wxString lmScore::DumpMidiEvents()
 
572
{
 
573
    if (!m_pSoundMngr) ComputeMidiEvents();
 
574
    return m_pSoundMngr->DumpMidiEvents();
 
575
}
 
576