~s-cecilio/lenmus/v5.3

« back to all changes in this revision

Viewing changes to src/sound/lenmus_midi_server.cpp

  • Committer: cecilios
  • Date: 2011-08-18 15:04:04 UTC
  • Revision ID: svn-v4:2587a929-2f0e-0410-ae78-fe6f687d5efe:branches/TRY-5.0:688
cleaning and commit recent work

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
//    the project at cecilios@users.sourceforge.net
18
18
//
19
19
//---------------------------------------------------------------------------------------
20
 
 
21
 
#include "lenmus_midi_server.h"
22
 
 
23
 
#include <wx/wxprec.h>
24
 
#include <wx/wx.h>
25
 
 
26
 
 
 
20
 
 
21
#include "lenmus_midi_server.h"
 
22
 
 
23
#include <wx/wxprec.h>
 
24
#include <wx/wx.h>
 
25
 
 
26
 
27
27
namespace lenmus
28
28
{
29
29
 
30
30
//=======================================================================================
31
 
// MidiServer implementation
 
31
// MidiServer implementation
32
32
//=======================================================================================
33
 
MidiServer::MidiServer(ApplicationScope& appScope)
34
 
    : m_appScope(appScope)
35
 
    , m_pMidiSystem(NULL)
36
 
    , m_pMidiIn(NULL)
37
 
    , m_pMidiOut(NULL)
38
 
{
39
 
    m_pMidiSystem = wxMidiSystem::GetInstance();
40
 
    LoadUserPreferences();
41
 
}
42
 
 
43
 
//---------------------------------------------------------------------------------------
44
 
MidiServer::~MidiServer()
45
 
{
46
 
    if (m_pMidiIn)
47
 
        m_pMidiIn->Close();
48
 
    if (m_pMidiOut)
49
 
        m_pMidiOut->Close();
50
 
 
51
 
    delete m_pMidiIn;
52
 
    delete m_pMidiOut;
53
 
    delete m_pMidiSystem;
54
 
}
55
 
 
56
 
//---------------------------------------------------------------------------------------
57
 
void MidiServer::LoadUserPreferences()
58
 
{
59
 
    //load settings form user congiguration data or default values
60
 
 
61
 
    wxConfigBase* pPrefs = m_appScope.get_preferences();
62
 
 
63
 
    pPrefs->Read(_T("/Midi/IsSet"), &m_fMidiSet, false );
64
 
 
65
 
    m_nOutDevId = (int)pPrefs->Read(_T("/Midi/OutDevice"), (long)0);            // 0 based. So this is device 1
66
 
    m_nVoiceChannel = (int)pPrefs->Read(_T("/Midi/VoiceChannel"), (long)0);    // 0 based. So this is channel 1
67
 
    m_nVoiceInstr = (int)pPrefs->Read(_T("/Midi/VoiceInstr"), (long)0);        // 0 based. So this is instrument 1 (grand piano)
68
 
 
69
 
    m_nMtrChannel = (int)pPrefs->Read(_T("/Midi/MtrChannel"), 9);        // 0 based. So this is channel 10
70
 
    m_nMtrInstr = (int)pPrefs->Read(_T("/Midi/MtrInstr"), (long)0);    // 0 based. So this is instrument 1 (grand piano)
71
 
    m_nMtrTone1 = (int)pPrefs->Read(_T("/Midi/MtrTone1"), 60L);        // 60-High bongo
72
 
    m_nMtrTone2 = (int)pPrefs->Read(_T("/Midi/MtrTone2"), 61L);        // 61-low bongo
73
 
 
74
 
    m_nInDevId = (int)pPrefs->Read(_T("/Midi/InDevice"), (long)0);    // 0 based. So this is device 1
75
 
 
76
 
        m_nDefaultVoiceChannel = m_nVoiceChannel;
77
 
        m_nDefaultVoiceInstr = m_nVoiceInstr;
78
 
 
79
 
    //sanity checks in case configuration file is corrupted
80
 
    if (m_nVoiceChannel < 0 || m_nVoiceChannel > 15) m_nVoiceChannel = 0;
81
 
    if (m_nVoiceInstr < 0 || m_nVoiceInstr > 255) m_nVoiceInstr = 0;
82
 
    if (m_nMtrChannel < 0 || m_nMtrChannel > 15) m_nMtrChannel = 9;
83
 
    if (m_nMtrInstr < 0 || m_nMtrInstr > 255) m_nMtrInstr = 0;
84
 
    if (m_nMtrTone1 < 0 || m_nMtrTone1 > 255) m_nMtrTone1 = 60;
85
 
    if (m_nMtrTone2 < 0 || m_nMtrTone2 > 255) m_nMtrTone2 = 61;
86
 
}
87
 
 
88
 
//---------------------------------------------------------------------------------------
89
 
void MidiServer::SaveUserPreferences()
90
 
{
91
 
    //save settings in user congiguration data
92
 
 
93
 
    wxConfigBase* pPrefs = m_appScope.get_preferences();
94
 
 
95
 
    pPrefs->Write(_T("/Midi/IsSet"), m_fMidiSet );
96
 
    pPrefs->Write(_T("/Midi/InDevice"), (long)m_nInDevId );
97
 
    pPrefs->Write(_T("/Midi/OutDevice"), (long)m_nOutDevId );
98
 
    pPrefs->Write(_T("/Midi/VoiceChannel"), (long)m_nVoiceChannel );
99
 
    pPrefs->Write(_T("/Midi/VoiceInstr"), (long)m_nVoiceInstr );
100
 
    pPrefs->Write(_T("/Midi/MtrChannel"), (long)m_nMtrChannel );
101
 
    pPrefs->Write(_T("/Midi/MtrInstr"), (long)m_nMtrInstr );
102
 
    pPrefs->Write(_T("/Midi/MtrTone1"), (long)m_nMtrTone1 );
103
 
    pPrefs->Write(_T("/Midi/MtrTone2"), (long)m_nMtrTone2 );
104
 
 
105
 
        m_nDefaultVoiceChannel = m_nVoiceChannel;
106
 
        m_nDefaultVoiceInstr = m_nVoiceInstr;
107
 
}
108
 
 
109
 
//---------------------------------------------------------------------------------------
110
 
void MidiServer::SetUpCurrentConfig()
111
 
{
112
 
    //int nInDev = m_nInDevId;    //save current Id
113
 
    m_nInDevId = -1;            //mark as 'not set yet'
114
 
 
115
 
    int nOutDev = m_nOutDevId;    //save current Id
116
 
    m_nOutDevId = -1;            //mark as 'not set yet'
117
 
    SetUpMidiOut(nOutDev, m_nVoiceChannel, m_nVoiceInstr);
118
 
}
119
 
 
120
 
//---------------------------------------------------------------------------------------
121
 
void MidiServer::SetOutDevice(int nOutDevId)
122
 
{
123
 
    wxMidiError nErr;
124
 
 
125
 
    //if out device Id has changed close current device and open the new one
126
 
    if (!m_pMidiOut || (m_nOutDevId != nOutDevId))
127
 
    {
128
 
        //close current device
129
 
         if (m_pMidiOut) 
130
 
         {
131
 
            nErr = m_pMidiOut->Close();
132
 
            delete m_pMidiOut;
133
 
            m_pMidiOut = NULL;
134
 
            //TODO better error reporting
135
 
            if (nErr) 
136
 
            {
137
 
                wxMessageBox( wxString::Format(
138
 
                    _T("Error %d in Open: %s \n")
139
 
                    , nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
140
 
                m_fMidiOK = false;
141
 
                return;
142
 
            }
143
 
        }
144
 
 
145
 
        //open new one
146
 
        m_nOutDevId = nOutDevId;
147
 
        if (m_nOutDevId != -1) 
148
 
        {
149
 
            m_pMidiOut = new wxMidiOutDevice(m_nOutDevId);
150
 
            // open output device
151
 
            nErr = m_pMidiOut->Open(0, NULL);        // 0 latency, no driver user info
152
 
            //TODO better error reporting
153
 
            if (nErr) 
154
 
            {
155
 
                                wxLogMessage(_T("Error %d opening Midi device"));
156
 
                //wxMessageBox( wxString::Format(
157
 
                //    _T("Error %d in Open: %s \n"),
158
 
                //    nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
159
 
                m_fMidiOK = false;
160
 
                return;
161
 
            }
162
 
        }
163
 
    }
164
 
}
165
 
 
166
 
//---------------------------------------------------------------------------------------
167
 
void MidiServer::SetInDevice(int nInDevId)
168
 
{
169
 
    wxMidiError nErr;
170
 
 
171
 
    //if in device Id has changed close current device and open the new one
172
 
    if (!m_pMidiIn || (m_nInDevId != nInDevId))
173
 
    {
174
 
        //close current device
175
 
         if (m_pMidiIn) 
176
 
         {
177
 
            nErr = m_pMidiIn->Close();
178
 
            delete m_pMidiIn;
179
 
            m_pMidiIn = NULL;
180
 
            //TODO better error reporting
181
 
            if (nErr) 
182
 
            {
183
 
                wxMessageBox( wxString::Format(
184
 
                    _T("Error %d in Open: %s \n"),
185
 
                    nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
186
 
                m_fMidiOK = false;
187
 
                return;
188
 
            }
189
 
        }
190
 
 
191
 
        //open new one
192
 
        m_nInDevId = nInDevId;
193
 
        if (m_nInDevId != -1) 
194
 
        {
195
 
            m_pMidiIn = new wxMidiInDevice(m_nInDevId);
196
 
            // open input device
197
 
            nErr = m_pMidiIn->Open(NULL);        // 0 latency, no driver user info
198
 
            //TODO better error reporting
199
 
            if (nErr) 
200
 
            {
201
 
                wxMessageBox( wxString::Format(
202
 
                    _T("Error %d in Open: %s \n")
203
 
                    , nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
204
 
                m_fMidiOK = false;
205
 
                return;
206
 
            }
207
 
        }
208
 
    }
209
 
}
210
 
 
211
 
//---------------------------------------------------------------------------------------
212
 
void MidiServer::SetUpMidiOut(int nOutDevId, int nChannel, int nInstrument)
213
 
{
214
 
    //open the new out device
215
 
    SetOutDevice(nOutDevId);
216
 
 
217
 
    //program new voices
218
 
    VoiceChange(nChannel, nInstrument);
219
 
}
220
 
 
221
 
//---------------------------------------------------------------------------------------
222
 
void MidiServer::VoiceChange(int nChannel, int nInstrument)
223
 
{
224
 
    //save new channel and instrument
225
 
    m_nVoiceChannel = nChannel;
226
 
    m_nVoiceInstr = nInstrument;
227
 
 
228
 
    //program new voices
229
 
    if (m_pMidiOut) 
230
 
    {
231
 
        wxMidiError nErr = m_pMidiOut->ProgramChange(m_nVoiceChannel, m_nVoiceInstr);
232
 
        //TODO error reporting eLocalError
233
 
        if (nErr) 
234
 
        {
235
 
            wxMessageBox( wxString::Format(
236
 
                                _T("Error %d in ProgramChange:\n%s")
237
 
                , nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
238
 
        }
239
 
    }
240
 
 
241
 
    m_fMidiOK = true;
242
 
}
243
 
 
244
 
//---------------------------------------------------------------------------------------
245
 
void MidiServer::SetMetronomeTones(int nTone1, int nTone2)
246
 
{
247
 
    m_nMtrTone1 = nTone1;
248
 
    m_nMtrTone2 = nTone2;
249
 
}
250
 
 
251
 
//---------------------------------------------------------------------------------------
252
 
void MidiServer::TestOut()
253
 
{
254
 
    if (!m_pMidiOut) return;
255
 
 
256
 
    //Play a scale
257
 
    int scale[] = { 60, 62, 64, 65, 67, 69, 71, 72 };
258
 
    #define SCALE_SIZE 8
259
 
 
260
 
    for (int i = 0; i < SCALE_SIZE; i++) 
261
 
    {
262
 
        m_pMidiOut->NoteOn(m_nVoiceChannel, scale[i], 100);
263
 
        ::wxMilliSleep(200);    // wait 200ms
264
 
        m_pMidiOut->NoteOff(m_nVoiceChannel, scale[i], 100);
265
 
    }
266
 
}
267
 
 
268
 
//---------------------------------------------------------------------------------------
269
 
int MidiServer::CountDevices()
270
 
{
271
 
    return m_pMidiSystem->CountDevices();
272
 
}
273
 
 
 
33
MidiServer::MidiServer(ApplicationScope& appScope)
 
34
    : m_appScope(appScope)
 
35
    , m_pMidiSystem(NULL)
 
36
    , m_pMidiIn(NULL)
 
37
    , m_pMidiOut(NULL)
 
38
{
 
39
    m_pMidiSystem = wxMidiSystem::GetInstance();
 
40
    LoadUserPreferences();
 
41
}
 
42
 
 
43
//---------------------------------------------------------------------------------------
 
44
MidiServer::~MidiServer()
 
45
{
 
46
    if (m_pMidiIn)
 
47
        m_pMidiIn->Close();
 
48
    if (m_pMidiOut)
 
49
        m_pMidiOut->Close();
 
50
 
 
51
    delete m_pMidiIn;
 
52
    delete m_pMidiOut;
 
53
    delete m_pMidiSystem;
 
54
}
 
55
 
 
56
//---------------------------------------------------------------------------------------
 
57
void MidiServer::LoadUserPreferences()
 
58
{
 
59
    //load settings form user congiguration data or default values
 
60
 
 
61
    wxConfigBase* pPrefs = m_appScope.get_preferences();
 
62
 
 
63
    pPrefs->Read(_T("/Midi/IsSet"), &m_fMidiSet, false );
 
64
 
 
65
    m_nOutDevId = (int)pPrefs->Read(_T("/Midi/OutDevice"), (long)0);            // 0 based. So this is device 1
 
66
    m_nVoiceChannel = (int)pPrefs->Read(_T("/Midi/VoiceChannel"), (long)0);    // 0 based. So this is channel 1
 
67
    m_nVoiceInstr = (int)pPrefs->Read(_T("/Midi/VoiceInstr"), (long)0);        // 0 based. So this is instrument 1 (grand piano)
 
68
 
 
69
    m_nMtrChannel = (int)pPrefs->Read(_T("/Midi/MtrChannel"), 9);        // 0 based. So this is channel 10
 
70
    m_nMtrInstr = (int)pPrefs->Read(_T("/Midi/MtrInstr"), (long)0);    // 0 based. So this is instrument 1 (grand piano)
 
71
    m_nMtrTone1 = (int)pPrefs->Read(_T("/Midi/MtrTone1"), 60L);        // 60-High bongo
 
72
    m_nMtrTone2 = (int)pPrefs->Read(_T("/Midi/MtrTone2"), 61L);        // 61-low bongo
 
73
 
 
74
    m_nInDevId = (int)pPrefs->Read(_T("/Midi/InDevice"), (long)0);    // 0 based. So this is device 1
 
75
 
 
76
        m_nDefaultVoiceChannel = m_nVoiceChannel;
 
77
        m_nDefaultVoiceInstr = m_nVoiceInstr;
 
78
 
 
79
    //sanity checks in case configuration file is corrupted
 
80
    if (m_nVoiceChannel < 0 || m_nVoiceChannel > 15) m_nVoiceChannel = 0;
 
81
    if (m_nVoiceInstr < 0 || m_nVoiceInstr > 255) m_nVoiceInstr = 0;
 
82
    if (m_nMtrChannel < 0 || m_nMtrChannel > 15) m_nMtrChannel = 9;
 
83
    if (m_nMtrInstr < 0 || m_nMtrInstr > 255) m_nMtrInstr = 0;
 
84
    if (m_nMtrTone1 < 0 || m_nMtrTone1 > 255) m_nMtrTone1 = 60;
 
85
    if (m_nMtrTone2 < 0 || m_nMtrTone2 > 255) m_nMtrTone2 = 61;
 
86
}
 
87
 
 
88
//---------------------------------------------------------------------------------------
 
89
void MidiServer::SaveUserPreferences()
 
90
{
 
91
    //save settings in user congiguration data
 
92
 
 
93
    wxConfigBase* pPrefs = m_appScope.get_preferences();
 
94
 
 
95
    pPrefs->Write(_T("/Midi/IsSet"), m_fMidiSet );
 
96
    pPrefs->Write(_T("/Midi/InDevice"), (long)m_nInDevId );
 
97
    pPrefs->Write(_T("/Midi/OutDevice"), (long)m_nOutDevId );
 
98
    pPrefs->Write(_T("/Midi/VoiceChannel"), (long)m_nVoiceChannel );
 
99
    pPrefs->Write(_T("/Midi/VoiceInstr"), (long)m_nVoiceInstr );
 
100
    pPrefs->Write(_T("/Midi/MtrChannel"), (long)m_nMtrChannel );
 
101
    pPrefs->Write(_T("/Midi/MtrInstr"), (long)m_nMtrInstr );
 
102
    pPrefs->Write(_T("/Midi/MtrTone1"), (long)m_nMtrTone1 );
 
103
    pPrefs->Write(_T("/Midi/MtrTone2"), (long)m_nMtrTone2 );
 
104
 
 
105
        m_nDefaultVoiceChannel = m_nVoiceChannel;
 
106
        m_nDefaultVoiceInstr = m_nVoiceInstr;
 
107
 
 
108
        pPrefs->Flush();
 
109
}
 
110
 
 
111
//---------------------------------------------------------------------------------------
 
112
void MidiServer::SetUpCurrentConfig()
 
113
{
 
114
    //int nInDev = m_nInDevId;    //save current Id
 
115
    m_nInDevId = -1;            //mark as 'not set yet'
 
116
 
 
117
    int nOutDev = m_nOutDevId;    //save current Id
 
118
    m_nOutDevId = -1;            //mark as 'not set yet'
 
119
    SetUpMidiOut(nOutDev, m_nVoiceChannel, m_nVoiceInstr);
 
120
}
 
121
 
 
122
//---------------------------------------------------------------------------------------
 
123
void MidiServer::SetOutDevice(int nOutDevId)
 
124
{
 
125
    wxMidiError nErr;
 
126
 
 
127
    //if out device Id has changed close current device and open the new one
 
128
    if (!m_pMidiOut || (m_nOutDevId != nOutDevId))
 
129
    {
 
130
        //close current device
 
131
         if (m_pMidiOut)
 
132
         {
 
133
            nErr = m_pMidiOut->Close();
 
134
            delete m_pMidiOut;
 
135
            m_pMidiOut = NULL;
 
136
            //TODO better error reporting
 
137
            if (nErr)
 
138
            {
 
139
                wxMessageBox( wxString::Format(
 
140
                    _T("Error %d in Open: %s \n")
 
141
                    , nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
 
142
                m_fMidiOK = false;
 
143
                return;
 
144
            }
 
145
        }
 
146
 
 
147
        //open new one
 
148
        wxLogMessage(_T("[MidiServer::SetOutDevice] Setting out Midi device: %d"), nOutDevId);
 
149
        m_nOutDevId = nOutDevId;
 
150
        if (m_nOutDevId != -1)
 
151
        {
 
152
            try
 
153
            {
 
154
                m_pMidiOut = new wxMidiOutDevice(m_nOutDevId);
 
155
                nErr = m_pMidiOut->Open(0, NULL);        // 0 latency, no driver user info
 
156
            }
 
157
            catch(...)      //handle all exceptions
 
158
            {
 
159
                                wxLogMessage(_T("[MidiServer::SetOutDevice] Crash opening Midi device"));
 
160
                                return;
 
161
            }
 
162
            //TODO better error reporting
 
163
            if (nErr)
 
164
            {
 
165
                                wxLogMessage(_T("[MidiServer::SetOutDevice] Error %d opening Midi device"), nErr);
 
166
                //wxMessageBox( wxString::Format(
 
167
                //    _T("Error %d in Open: %s \n"),
 
168
                //    nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
 
169
                m_fMidiOK = false;
 
170
                return;
 
171
            }
 
172
            else
 
173
                                wxLogMessage(_T("[MidiServer::SetOutDevice] Midi out device correctly set."));
 
174
        }
 
175
    }
 
176
}
 
177
 
 
178
//---------------------------------------------------------------------------------------
 
179
void MidiServer::SetInDevice(int nInDevId)
 
180
{
 
181
    wxMidiError nErr;
 
182
 
 
183
    //if in device Id has changed close current device and open the new one
 
184
    if (!m_pMidiIn || (m_nInDevId != nInDevId))
 
185
    {
 
186
        //close current device
 
187
         if (m_pMidiIn)
 
188
         {
 
189
            nErr = m_pMidiIn->Close();
 
190
            delete m_pMidiIn;
 
191
            m_pMidiIn = NULL;
 
192
            //TODO better error reporting
 
193
            if (nErr)
 
194
            {
 
195
                wxMessageBox( wxString::Format(
 
196
                    _T("Error %d in Open: %s \n"),
 
197
                    nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
 
198
                m_fMidiOK = false;
 
199
                return;
 
200
            }
 
201
        }
 
202
 
 
203
        //open new one
 
204
        m_nInDevId = nInDevId;
 
205
        if (m_nInDevId != -1)
 
206
        {
 
207
            m_pMidiIn = new wxMidiInDevice(m_nInDevId);
 
208
            // open input device
 
209
            nErr = m_pMidiIn->Open(NULL);        // 0 latency, no driver user info
 
210
            //TODO better error reporting
 
211
            if (nErr)
 
212
            {
 
213
                wxMessageBox( wxString::Format(
 
214
                    _T("Error %d in Open: %s \n")
 
215
                    , nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
 
216
                m_fMidiOK = false;
 
217
                return;
 
218
            }
 
219
        }
 
220
    }
 
221
}
 
222
 
 
223
//---------------------------------------------------------------------------------------
 
224
void MidiServer::SetUpMidiOut(int nOutDevId, int nChannel, int nInstrument)
 
225
{
 
226
    //open the new out device
 
227
    SetOutDevice(nOutDevId);
 
228
 
 
229
    //program new voices
 
230
    VoiceChange(nChannel, nInstrument);
 
231
}
 
232
 
 
233
//---------------------------------------------------------------------------------------
 
234
void MidiServer::VoiceChange(int nChannel, int nInstrument)
 
235
{
 
236
    //save new channel and instrument
 
237
    m_nVoiceChannel = nChannel;
 
238
    m_nVoiceInstr = nInstrument;
 
239
 
 
240
    //program new voices
 
241
    if (m_pMidiOut)
 
242
    {
 
243
        wxMidiError nErr = m_pMidiOut->ProgramChange(m_nVoiceChannel, m_nVoiceInstr);
 
244
        //TODO error reporting eLocalError
 
245
        if (nErr)
 
246
        {
 
247
            wxMessageBox( wxString::Format(
 
248
                                _T("Error %d in ProgramChange:\n%s")
 
249
                , nErr, m_pMidiSystem->GetErrorText(nErr).c_str() ));
 
250
        }
 
251
    }
 
252
 
 
253
    m_fMidiOK = true;
 
254
}
 
255
 
 
256
//---------------------------------------------------------------------------------------
 
257
void MidiServer::SetMetronomeTones(int nTone1, int nTone2)
 
258
{
 
259
    m_nMtrTone1 = nTone1;
 
260
    m_nMtrTone2 = nTone2;
 
261
}
 
262
 
 
263
//---------------------------------------------------------------------------------------
 
264
void MidiServer::TestOut()
 
265
{
 
266
    if (!m_pMidiOut) return;
 
267
 
 
268
    //Play a scale
 
269
    int scale[] = { 60, 62, 64, 65, 67, 69, 71, 72 };
 
270
    #define SCALE_SIZE 8
 
271
 
 
272
    for (int i = 0; i < SCALE_SIZE; i++)
 
273
    {
 
274
        m_pMidiOut->NoteOn(m_nVoiceChannel, scale[i], 100);
 
275
        ::wxMilliSleep(200);    // wait 200ms
 
276
        m_pMidiOut->NoteOff(m_nVoiceChannel, scale[i], 100);
 
277
    }
 
278
}
 
279
 
 
280
//---------------------------------------------------------------------------------------
 
281
int MidiServer::CountDevices()
 
282
{
 
283
    return m_pMidiSystem->CountDevices();
 
284
}
 
285
 
274
286
 
275
287
}   //namespace lenmus
276
 
 
 
288