File: tst_sfzloop.cpp

package info (click to toggle)
musescore2 2.3.2%2Bdfsg4-16
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 170,464 kB
  • sloc: cpp: 262,612; xml: 176,707; sh: 3,377; ansic: 1,246; python: 356; makefile: 227; perl: 82; pascal: 78
file content (179 lines) | stat: -rw-r--r-- 7,432 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

//=============================================================================
//  MuseScore
//  Music Composition & Notation
//  $Id:$
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License version 2
//  as published by the Free Software Foundation and appearing in
//  the file LICENCE.GPL
//=============================================================================

#include <QtTest/QtTest>

#include "mtest/testutils.h"

#include "zerberus/instrument.h"
#include "zerberus/zerberus.h"
#include "zerberus/zone.h"
#include "mscore/preferences.h"
#include "synthesizer/event.h"
#include <sndfile.h>

using namespace Ms;

//---------------------------------------------------------
//   TestSfzEnvelopes
//---------------------------------------------------------

class TestSfzLoop : public QObject, public MTest
      {
      Q_OBJECT
      float samplerate = 44100;
      Zerberus* synth;

   private slots:
      void initTestCase();
      void testEnvelopesParsing();
      void testLoopAudio();
   public:
      ~TestSfzLoop();
      };

//---------------------------------------------------------
//   initTestCase
//---------------------------------------------------------

void TestSfzLoop::initTestCase()
      {
      initMTest();
      synth = new Zerberus();
      synth->init(samplerate);
      Ms::preferences.mySoundfontsPath += ";" + root;
      synth->loadInstrument("loopTest.sfz");
      }

//---------------------------------------------------------
//   testglobal
//---------------------------------------------------------

void TestSfzLoop::testEnvelopesParsing()
      {
      QCOMPARE(synth->instrument(0)->zones().size(), (unsigned long) 4);

      std::list<Zone *>::iterator curZone = synth->instrument(0)->zones().begin();
      QCOMPARE((*curZone)->keyLo, (char) 20);
      QCOMPARE((*curZone)->keyHi, (char) 20);
      QCOMPARE((*curZone)->keyBase, (char) 20);
      QCOMPARE((*curZone)->loopMode, LoopMode::NO_LOOP);
      curZone++;

      QCOMPARE((*curZone)->keyLo, (char) 21);
      QCOMPARE((*curZone)->keyHi, (char) 21);
      QCOMPARE((*curZone)->keyBase, (char) 21);
      QCOMPARE((*curZone)->loopMode, LoopMode::ONE_SHOT);
      curZone++;

      QCOMPARE((*curZone)->keyLo, (char) 22);
      QCOMPARE((*curZone)->keyHi, (char) 22);
      QCOMPARE((*curZone)->keyBase, (char) 22);
      QCOMPARE((*curZone)->loopMode, LoopMode::CONTINUOUS);
      curZone++;

      QCOMPARE((*curZone)->keyLo, (char) 23);
      QCOMPARE((*curZone)->keyHi, (char) 23);
      QCOMPARE((*curZone)->keyBase, (char) 23);
      QCOMPARE((*curZone)->loopMode, LoopMode::SUSTAIN);
      curZone++;
      }

void TestSfzLoop::testLoopAudio()
      {
      synth->play(Ms::PlayEvent(ME_PROGRAM, 0, 0, 0));
      float data[2 * 110 * 3]; // 2 Channel 110 Sample duration - enough space for at least one loop
      memset(data, 0, sizeof(data));

      // test no_loop
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 20, 127)); // play note - no_loop mode
      synth->process(50, data, nullptr, nullptr); // process - stop in middle of ones
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 20, 0)); // send note off and check whether voice is actually turned off
      synth->process(50 , data + (50*2), nullptr, nullptr); // process until end of sustain stage
      QCOMPARE(data[0], 0.0f);
      QCOMPARE(data[1], 0.0f);
      QCOMPARE(data[10 * 2] != 0.0f, true);
      QCOMPARE(data[10 * 2 + 1] != 0.0f, true);
      QCOMPARE(data[50 * 2], 0.0f);
      QCOMPARE(data[50 * 2 + 1], 0.0f);
      memset(data, 0, sizeof(data)); // clear data because each voice gets added to it!

      // test one_shot
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 21, 127)); // play note - one_shot
      synth->process(50, data, nullptr, nullptr); // process - stop in middle of ones
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 21, 0)); // send note off - sample should still play to end!
      synth->process(60 , data + (50*2), nullptr, nullptr); // process until end of sample
      QCOMPARE(data[0], 0.0f);
      QCOMPARE(data[1], 0.0f);
      QVERIFY(data[10 * 2] != 0.0f);
      QVERIFY(data[10 * 2 + 1] != 0.0f);
      QVERIFY(data[50 * 2] != 0.0f);
      QVERIFY(data[50 * 2 + 1] != 0.0f);
      QVERIFY(data[60 * 2] > pow(10, -30.0f/20.0f)); // it is not zero due to the filter - assume at least -30dB right after stop
      QVERIFY(data[60 * 2 + 1] > pow(10, -30.0f/20.0f));
      QVERIFY(data[70 * 2] < pow(10, -85.0f/20.0f)); // and -85dB 10 samples later
      QVERIFY(data[70 * 2 + 1] < pow(10, -85.0f/20.0f));
      memset(data, 0, sizeof(data)); // clear data because each voice gets added to it!

      // test loop_continuous
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 22, 127)); // play note
      synth->process(109, data, nullptr, nullptr); // process - it should loop (loop from 10 to 59)
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 22, 0)); // send note off - sample should not switch to the zero part
      synth->process(60 , data + (109*2), nullptr, nullptr); // process until end of release
      QCOMPARE(data[0], 0.0f);
      QCOMPARE(data[1], 0.0f);
      QVERIFY(data[10 * 2] != 0.0f);
      QVERIFY(data[10 * 2 + 1] != 0.0f);
      QVERIFY(data[50 * 2] != 0.0f);
      QVERIFY(data[50 * 2 + 1] != 0.0f);
      QVERIFY(data[60 * 2] > pow(10, -15.0f/20.0f)); // it should not stop make sure it is loud enough!
      QVERIFY(data[60 * 2 + 1] > pow(10, -15.0f/20.0f));
      QVERIFY(data[70 * 2] > pow(10, -15.0f/20.0f)); // it should not stop make sure it is loud enough!
      QVERIFY(data[70 * 2 + 1] > pow(10, -15.0f/20.0f));
      QVERIFY(data[110 * 2] > pow(10, -20.0f/20.0f)); // it should not stop make sure it is loud enough!
      QVERIFY(data[110 * 2 + 1] > pow(10, -20.0f/20.0f));
      QVERIFY(data[120 * 2] > pow(10, -35.0f/20.0f)); // it should not stop make sure it is loud enough!
      QVERIFY(data[120 * 2 + 1] > pow(10, -35.0f/20.0f));
      memset(data, 0, sizeof(data)); // clear data because each voice gets added to it!

      // test loop_sustain
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 23, 127)); // play note
      synth->process(109, data, nullptr, nullptr); // process - it should loop (loop from 10 to 59)
      synth->play(Ms::PlayEvent(ME_NOTEON, 0, 23, 0)); // send note off - sample should not switch to the zero part
      synth->process(60 , data + (109*2), nullptr, nullptr); // process until end of release
      QCOMPARE(data[0], 0.0f);
      QCOMPARE(data[1], 0.0f);
      QVERIFY(data[10 * 2] != 0.0f);
      QVERIFY(data[10 * 2 + 1] != 0.0f);
      QVERIFY(data[50 * 2] != 0.0f);
      QVERIFY(data[50 * 2 + 1] != 0.0f);
      QVERIFY(data[60 * 2] > pow(10, -15.0f/20.0f)); // it should not stop make sure it is loud enough!
      QVERIFY(data[60 * 2 + 1] > pow(10, -15.0f/20.0f));
      QVERIFY(data[70 * 2] > pow(10, -15.0f/20.0f)); // it should not stop make sure it is loud enough!
      QVERIFY(data[70 * 2 + 1] > pow(10, -15.0f/20.0f));
      QVERIFY(data[110 * 2] < pow(10, -20.0f/20.0f)); // it should play zeros after leaving sustain -> drastic volume reduce
      QVERIFY(data[110 * 2 + 1] < pow(10, -20.0f/20.0f));
      QVERIFY(data[120 * 2] < pow(10, -85.0f/20.0f));
      QVERIFY(data[120 * 2 + 1] < pow(10, -85.0f/20.0f));

      }

TestSfzLoop::~TestSfzLoop()
      {
      delete synth;
      }

QTEST_MAIN(TestSfzLoop)

#include "tst_sfzloop.moc"