1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: s1.cpp,v 1.9.2.5 2009/11/19 04:20:33 terminator356 Exp $
5 //
6 //    S1  - simple mono demo synthesizer
7 //        - plays only one note at a time
8 //        - has no gui nor any controller
9 //
10 //    Version 0.2: stop note on wave zero crossing to avoid
11 //                 clicks
12 //
13 //  (C) Copyright 2001-2004 Werner Schweer (ws@seh.de)
14 //
15 //  This program is free software; you can redistribute it and/or
16 //  modify it under the terms of the GNU General Public License
17 //  as published by the Free Software Foundation; version 2 of
18 //  the License, or (at your option) any later version.
19 //
20 //  This program is distributed in the hope that it will be useful,
21 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
22 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 //  GNU General Public License for more details.
24 //
25 //  You should have received a copy of the GNU General Public License
26 //  along with this program; if not, write to the Free Software
27 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
28 //
29 //=========================================================
30 
31 #include <list>
32 
33 #include <QMessageBox>
34 
35 #include "muse_math.h"
36 #include "libsynti/mono.h"
37 
38 #define RESOLUTION   16384
39 // Make sure this number is unique among all the MESS synths (including ticksynth) and DSSI, VST, LV2 and other host synths.
40 // 127 is reserved for special MusE system messages.
41 #define S1_UNIQUE_ID      6
42 
43 
44 //---------------------------------------------------------
45 //   S1 - simple mono demo synthesizer
46 //---------------------------------------------------------
47 
48 
49 class S1 : public MessMono {
50       static int useCount;
51       static float *wave_table;
52 
53       int gate;
54       float freq;
55       unsigned accu;
56       float sample;
57       bool _showGui;
58 
59       int param;
60 
61       virtual void note(int channel, int pitch, int velo);
62       //virtual void processMessages();
63       virtual void process(unsigned pos, float** buffer, int offset, int n);
hasNativeGui() const64       virtual bool hasNativeGui() const { return true; }
nativeGuiVisible() const65       virtual bool nativeGuiVisible() const { return _showGui; }
66       virtual void showNativeGui(bool);
67       virtual bool setController(int channel, int ctrl, int val);
68       virtual int getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval) const;
69 
70    public:
71       S1();
72       virtual ~S1();
73       };
74 
75 float* S1::wave_table;
76 int S1::useCount = 0;
77 
78 //---------------------------------------------------------
79 //   S1
80 //---------------------------------------------------------
81 
S1()82 S1::S1() : MessMono()
83       {
84 
85       if (useCount++ == 0) {
86             //
87             // create sinus wave table
88             //
89             wave_table = new float[RESOLUTION];
90             for (int i = 0; i < RESOLUTION; i++)
91                   wave_table[i] = sin ((i * 2.0 * M_PI) / RESOLUTION) / 6.0;
92             }
93       gate = 0;
94 
95       param = 0;
96 
97       _showGui=false;
98       showNativeGui(true);
99       }
100 
101 //---------------------------------------------------------
102 //   ~S1
103 //---------------------------------------------------------
104 
~S1()105 S1::~S1()
106       {
107       if (--useCount == 0)
108             delete[] wave_table;
109       }
110 
111 //---------------------------------------------------------
112 //   noteon
113 //    process note on
114 //---------------------------------------------------------
115 
note(int,int pitch,int velo)116 void S1::note(int /*channel*/, int pitch, int velo)
117       {
118       if (velo == 0) {
119             //
120             // note off
121             //
122             if (sample == 0.0)
123                   gate = 0;
124             else if (sample > 0.0)
125                   gate = 2;
126             else if (sample < 0.0)
127                   gate = 3;
128             }
129       else {
130             //
131             // note on
132             //
133             accu     = 0;
134             gate     = 1;
135             freq     = 8.176 * exp(float(pitch)*log(2.0)/12.0);
136             }
137       }
138 
139 //---------------------------------------------------------
140 //   write
141 //    synthesize n samples into buffer+offset
142 //---------------------------------------------------------
143 
process(unsigned,float ** buffer,int offset,int n)144 void S1::process(unsigned /*pos*/, float** buffer, int offset, int n)
145       {
146       if (gate == 0)
147             return;
148       float* p = buffer[0] + offset;
149       float sample1, sample2;
150       unsigned freq_256 = (int) (freq * ((double) RESOLUTION) / sampleRate() * 256.0);
151       for (int i = 0; i < n; i++) {
152             accu += freq_256;
153             while (accu >= RESOLUTION * 256)
154                   accu -= RESOLUTION * 256;
155 
156             sample1 = wave_table[accu >> 8]; // sinus component
157 
158             if (sample1< 0.0f) // square wave component
159               sample2 = -0.4;
160             else
161               sample2 = 0.4;
162 
163             sample = ((1.0-float(param)/127.0)*sample1 + (float(param)/127.0)*sample2) / 2.0;
164 
165             //
166             // stop on zero crossing
167             // if in decay state
168             //
169             if (gate == 2 && sample <= 0.0) {
170                   gate = 0;
171                   break;
172                   }
173             else if (gate == 3 && sample >= 0.0) {
174                   gate = 0;
175                   break;
176                   }
177             p[i] += sample;
178             }
179       }
180 
181 
182 //---------------------------------------------------------
183 //   inst
184 //---------------------------------------------------------
185 
186 
showNativeGui(bool show)187 void S1::showNativeGui(bool show)
188       {
189       if (show)
190         QMessageBox::information( NULL, "S1",
191         "S1 is a demo synth mainly for\n"
192         "developers wishing to learn\n"
193         "how to make a M.E.S.S synth.\n"
194         "\n"
195         "One modulation parameter is available,\n"
196         "it sweeps the signal between square and\n"
197         "sinus wave.\n", 1 );
198       }
199 
setController(int,int ctrl,int val)200 bool S1::setController(int, int ctrl, int val)
201       {
202       if (ctrl == 1) {
203              param = val;
204              }
205       return true;
206       }
207 
getControllerInfo(int id,const char ** name,int * ctrl,int * min,int * max,int * initval) const208 int S1::getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval) const
209       {
210         if (id == 0) {
211             *name = "Modulation";
212             *ctrl = 1;
213             *min = 0;
214             *max = 127;
215             *initval = 0;
216             return 1;
217             }
218         else
219           return 0;
220       }
221 
222 //---------------------------------------------------------
223 //   inst
224 //---------------------------------------------------------
225 class QWidget;
226 
227 
instantiate(unsigned long long,const char *,const MessConfig * config)228 static Mess* instantiate(unsigned long long /*parentWinId*/, const char* /*name*/, const MessConfig* config)
229       {
230       S1* s1 = new S1();
231       s1->setSampleRate(config->_sampleRate);
232       return s1;
233       }
234 
235 extern "C" {
236       static MESS descriptor = {
237             "S1",
238             "S1 MusE Demo Software Synthesizer",
239             "0.2",      // version string
240             MESS_MAJOR_VERSION, MESS_MINOR_VERSION,
241             instantiate
242             };
243       // We must compile with -fvisibility=hidden to avoid namespace
244       // conflicts with global variables.
245       // Only visible symbol is "mess_descriptor".
246       // (TODO: all plugins should be compiled this way)
247 
248       __attribute__ ((visibility("default")))
mess_descriptor()249       const MESS* mess_descriptor() { return &descriptor; }
250       }
251 
252