13ad0e2d0ed9fe94680d9b723e614c2c251c3aac
[stwbeast.git] / plugins / davorgan.cc
1 /* DavOrgan - DAV Additive Organ Synthesizer
2  * Copyright (c) 1999, 2000, 2002 David A. Bartold and Tim Janik
3  * Copyright (c) 2006-2007 Stefan Westerfeld
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * A copy of the GNU Lesser General Public License should ship along
16  * with this library; if not, see http://www.gnu.org/copyleft/.
17  */
18 #include "davorgan.genidl.hh"
19 #include <bse/bsemathsignal.h>
20 #include <bse/bsemain.h>
21 #include <vector>
22
23 namespace Bse {
24 namespace Dav {
25
26 using namespace Birnet;  // FIXME: move to Bse namespace
27 using Birnet::uint32;    // FIXME: move to Bse header
28
29 class Organ : public OrganBase {
30   /* per mix_freq() tables */
31   class Tables
32   {
33     vector<float> m_sine_table, m_triangle_table, m_pulse_table;
34     uint          m_ref_count, m_rate;
35     Tables (uint urate) :
36       m_sine_table (urate), m_triangle_table (urate), m_pulse_table (urate),
37       m_ref_count (1), m_rate (urate)
38     {
39       double rate = urate, half = rate / 2, slope = rate / 10;
40       int    i;
41       /* Initialize sine table. */
42       for (i = 0; i < rate; i++)
43         m_sine_table[i] = sin ((i / rate) * 2.0 * PI) / 6.0;
44       /* Initialize triangle table. */
45       for (i = 0; i < rate / 2; i++)
46         m_triangle_table[i] = (4 / rate * i - 1.0) / 6.0;
47       for (; i < rate; i++)
48         m_triangle_table[i] = (4 / rate * (rate - i) - 1.0) / 6.0;
49       /* Initialize beveled pulse table:  _
50        *                                 / \
51        *                              \_/
52        */
53       for (i = 0; i < slope; i++)
54         m_pulse_table[i] = (-i / slope) / 6.0;
55       for (; i < half - slope; i++)
56         m_pulse_table[i] = -1.0 / 6.0;
57       for (; i < half + slope; i++)
58         m_pulse_table[i] = ((i - half) / slope) / 6.0;
59       for (; i < rate - slope; i++)
60         m_pulse_table[i] = 1.0 / 6.0;
61       for (; i < rate; i++)
62         m_pulse_table[i] = ((rate - i) * 1.0 / slope) / 6.0;
63     }
64     ~Tables()
65     {} // private destructor; use ref_counting
66     static map<uint, Tables*> table_map;   /* rate -> rate specific tables */
67     static Mutex              table_mutex;
68   public:
69     static Tables*
70     ref (uint rate)
71     {
72       AutoLocker locker (table_mutex);
73       if (table_map[rate])
74         table_map[rate]->m_ref_count++;
75       else
76         table_map[rate] = new Tables (rate);
77       return table_map[rate];
78     }
79     void
80     unref()
81     {
82       return_if_fail (m_ref_count > 0);
83       AutoLocker locker (table_mutex);
84       if (--m_ref_count == 0)
85         {
86           table_map[m_rate] = 0;
87           delete this;
88         }
89     }
90     const float*
91     sine_table() const
92     {
93       return &m_sine_table[0];
94     }
95     const float*
96     triangle_table() const
97     {
98       return &m_triangle_table[0];
99     }
100     const float*
101     pulse_table() const
102     {
103       return &m_pulse_table[0];
104     }
105   };
106   /* FIXME: get rid of this as soon as the modules have their own current_musical_tuning() accessor */
107   struct Properties : public OrganProperties {
108     BseMusicalTuningType current_musical_tuning;
109     Properties (Organ *organ) :
110       OrganProperties (organ),
111       current_musical_tuning (organ->current_musical_tuning())
112     {}
113   };
114   class Module : public SynthesisModule {
115   public:
116     /* frequency */
117     double        m_transpose_factor, m_fine_tune_factor, m_base_freq;
118     /* instrument flavour */
119     bool          m_flute, m_reed, m_brass;
120     /* harmonics */
121     double        m_harm0, m_harm1, m_harm2, m_harm3, m_harm4, m_harm5;
122     /* phase accumulators */
123     uint32        m_harm0_paccu, m_harm1_paccu, m_harm2_paccu, m_harm3_paccu, m_harm4_paccu, m_harm5_paccu;
124     /* mix_freq() specific tables */
125     Tables       *m_tables;
126     Module() :
127       m_tables (Tables::ref (mix_freq()))
128     {}
129     ~Module()
130     {
131       m_tables->unref();
132       m_tables = NULL;
133     }
134     void
135     config (Properties *properties)
136     {
137       m_base_freq = properties->base_freq;
138       m_transpose_factor = bse_transpose_factor (properties->current_musical_tuning, properties->transpose);
139       m_fine_tune_factor = bse_cent_tune_fast (properties->fine_tune);
140       // percent -> factor conversions
141       m_harm0 = properties->harm0 / 100.0;
142       m_harm1 = properties->harm1 / 100.0;
143       m_harm2 = properties->harm2 / 100.0;
144       m_harm3 = properties->harm3 / 100.0;
145       m_harm4 = properties->harm4 / 100.0;
146       m_harm5 = properties->harm5 / 100.0;
147       m_flute = properties->flute;
148       m_reed = properties->reed;
149       m_brass = properties->brass;
150     }
151     void
152     reset()
153     {
154       uint32 rfactor = bse_main_args->allow_randomization ? 1 : 0;
155       uint32 mix_freq_256 = mix_freq() * 256;
156       /* to make all notes sound a bit different, randomize the initial phase of
157        * each harmonic (except if the user requested deterministic behaviour)
158        */
159       m_harm0_paccu = rfactor * g_random_int_range (0, mix_freq_256);
160       m_harm1_paccu = rfactor * g_random_int_range (0, mix_freq_256);
161       m_harm2_paccu = rfactor * g_random_int_range (0, mix_freq_256);
162       m_harm3_paccu = rfactor * g_random_int_range (0, mix_freq_256);
163       m_harm4_paccu = rfactor * g_random_int_range (0, mix_freq_256);
164       m_harm5_paccu = rfactor * g_random_int_range (0, mix_freq_256);
165     }
166     static inline float
167     table_pos (const float *table,
168                uint         freq_256,
169                uint         mix_freq_256,
170                uint32      *paccu)
171     {
172       *paccu += freq_256;
173       while (*paccu >= mix_freq_256)
174         *paccu -= mix_freq_256;
175
176       return table[*paccu >> 8];
177     }
178     inline uint
179     dfreq_to_freq_256 (double dfreq)
180     {
181       dfreq *= m_transpose_factor * m_fine_tune_factor;
182
183       /* Make sure that the actual sound generation code will only see
184        * frequencies in the range [0, mix_freq/2]. We map negative frequencies
185        * (like -440 Hz) to their positive equivalents (+440 Hz).
186        */
187       dfreq = min (fabs (dfreq), mix_freq() * 0.5);
188
189       /* round frequency with dtoi during conversion from floating point to our
190        * fixed point representation, in order to minimize the conversion error
191        */
192       return dtoi (dfreq * 256);
193     }
194     void
195     process (unsigned int n_values)
196     {
197       const float *sine_table = m_tables->sine_table();
198       const float *flute_table = m_flute ? m_tables->triangle_table() : sine_table;
199       const float *reed_table = m_reed ? m_tables->pulse_table() : sine_table;
200       const float *ifreq = istream (ICHANNEL_FREQ_IN).values;
201       float       *ovalues = ostream (OCHANNEL_AUDIO_OUT).values;
202       uint         freq_256;
203
204       if (istream (ICHANNEL_FREQ_IN).connected)
205         freq_256 = dfreq_to_freq_256 (BSE_FREQ_FROM_VALUE (ifreq[0]));
206       else
207         freq_256 = dfreq_to_freq_256 (m_base_freq);
208
209       uint mix_freq_256 = mix_freq() * 256;
210       uint freq_256_harm0 = freq_256 / 2;
211       uint freq_256_harm1 = freq_256;
212
213       if (m_brass)
214         {
215           uint freq_256_harm2 = freq_256 * 2;
216           uint freq_256_harm3 = freq_256_harm2 * 2;
217           uint freq_256_harm4 = freq_256_harm3 * 2;
218           uint freq_256_harm5 = freq_256_harm4 * 2;
219
220           for (uint i = 0; i < n_values; i++)
221             {
222               float vaccu;
223
224               vaccu  = table_pos (sine_table,  freq_256_harm0, mix_freq_256, &m_harm0_paccu) * m_harm0;
225               vaccu += table_pos (sine_table,  freq_256_harm1, mix_freq_256, &m_harm1_paccu) * m_harm1;
226               vaccu += table_pos (reed_table,  freq_256_harm2, mix_freq_256, &m_harm2_paccu) * m_harm2;
227               vaccu += table_pos (sine_table,  freq_256_harm3, mix_freq_256, &m_harm3_paccu) * m_harm3;
228               vaccu += table_pos (flute_table, freq_256_harm4, mix_freq_256, &m_harm4_paccu) * m_harm4;
229               vaccu += table_pos (flute_table, freq_256_harm5, mix_freq_256, &m_harm5_paccu) * m_harm5;
230               ovalues[i] = vaccu;
231             }
232         }
233       else
234         {
235           uint freq_256_harm2 = freq_256 * 3 / 2;
236           uint freq_256_harm3 = freq_256 * 2;
237           uint freq_256_harm4 = freq_256 * 3;
238           uint freq_256_harm5 = freq_256_harm3 * 2;
239
240           for (uint i = 0; i < n_values; i++)
241             {
242               float vaccu;
243
244               vaccu  = table_pos (sine_table,  freq_256_harm0, mix_freq_256, &m_harm0_paccu) * m_harm0;
245               vaccu += table_pos (sine_table,  freq_256_harm1, mix_freq_256, &m_harm1_paccu) * m_harm1;
246               vaccu += table_pos (sine_table,  freq_256_harm2, mix_freq_256, &m_harm2_paccu) * m_harm2;
247               vaccu += table_pos (reed_table,  freq_256_harm3, mix_freq_256, &m_harm3_paccu) * m_harm3;
248               vaccu += table_pos (sine_table,  freq_256_harm4, mix_freq_256, &m_harm4_paccu) * m_harm4;
249               vaccu += table_pos (flute_table, freq_256_harm5, mix_freq_256, &m_harm5_paccu) * m_harm5;
250               ovalues[i] = vaccu;
251             }
252         }
253     }
254   };
255 public:
256   bool
257   property_changed (OrganPropertyID prop_id)
258   {
259     switch (prop_id)
260       {
261       /* implement special handling of GUI properties */
262       case PROP_BASE_FREQ:
263         base_note = bse_note_from_freq (current_musical_tuning(), base_freq);
264         notify ("base_note");
265         break;
266       case PROP_BASE_NOTE:
267         base_freq = bse_note_to_freq (current_musical_tuning(), base_note);
268         notify ("base_freq");
269         break;
270       default: ;
271       }
272     return false;
273   }
274   /* implement creation and config methods for synthesis Module */
275   BSE_EFFECT_INTEGRATE_MODULE (Organ, Module, Properties);
276 };
277
278 map<uint, Organ::Tables*> Organ::Tables::table_map;
279 Mutex                     Organ::Tables::table_mutex;
280
281 BSE_CXX_DEFINE_EXPORTS();
282 BSE_CXX_REGISTER_EFFECT (Organ);
283
284 } // Dav
285 } // Bse