1 /*
2  * liquidsfz - sfz sampler
3  *
4  * Copyright (C) 2019  Stefan Westerfeld
5  *
6  * This library is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation; either version 2.1 of the License, or (at your
9  * option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "synth.hh"
22 #include "liquidsfz.hh"
23 
24 #include <stdarg.h>
25 
26 using LiquidSFZ::Log;
27 
28 using std::string;
29 using std::min;
30 
31 namespace LiquidSFZInternal {
32 
33 void
process_audio(float ** outputs,uint n_frames,uint offset)34 Synth::process_audio (float **outputs, uint n_frames, uint offset)
35 {
36   uint i = 0;
37   while (i < n_frames)
38     {
39       const uint todo = min (n_frames - i, MAX_BLOCK_SIZE);
40 
41       float *outputs_offset[] = {
42         outputs[0] + offset + i,
43         outputs[1] + offset + i
44       };
45 
46       for (auto& voice : voices_)
47         {
48           if (voice.state_ != Voice::IDLE)
49             voice.process (outputs_offset, todo);
50         }
51       i += todo;
52     }
53   global_frame_count += n_frames;
54 }
55 
56 void
process(float ** outputs,uint n_frames)57 Synth::process (float **outputs, uint n_frames)
58 {
59   std::fill_n (outputs[0], n_frames, 0.0);
60   std::fill_n (outputs[1], n_frames, 0.0);
61 
62   uint offset = 0;
63   for (const auto& event : events)
64     {
65       // ensure that new offset from event is not larger than n_frames
66       const uint new_offset = min <uint> (event.time_frames, n_frames);
67 
68       // process any audio that is before the event
69       process_audio (outputs, new_offset - offset, offset);
70       offset = new_offset;
71 
72       // process event at timestamp offset
73       switch (event.type)
74         {
75           case Event::Type::NOTE_ON:    note_on (event.channel, event.arg1, event.arg2);
76                                         break;
77           case Event::Type::NOTE_OFF:   note_off (event.channel, event.arg1);
78                                         break;
79           case Event::Type::CC:         update_cc (event.channel, event.arg1, event.arg2);
80                                         break;
81           case Event::Type::PITCH_BEND: update_pitch_bend (event.channel, event.arg1);
82                                         break;
83           default:                      debug ("process: unsupported event type %d\n", int (event.type));
84         }
85     }
86   events.clear();
87 
88   // process frames after last event
89   process_audio (outputs, n_frames - offset, offset);
90 }
91 
92 void
all_sound_off()93 Synth::all_sound_off()
94 {
95   for (auto& voice : voices_)
96     voice.kill();
97 }
98 
99 void
system_reset()100 Synth::system_reset()
101 {
102   all_sound_off();
103   init_channels();
104 }
105 
106 void
set_progress_function(std::function<void (double)> function)107 Synth::set_progress_function (std::function<void (double)> function)
108 {
109   progress_function_ = function;
110 }
111 
112 void
set_log_function(std::function<void (Log,const char *)> function)113 Synth::set_log_function (std::function<void (Log, const char *)> function)
114 {
115   log_function_ = function;
116 }
117 
118 void
set_log_level(Log log_level)119 Synth::set_log_level (Log log_level)
120 {
121   log_level_ = log_level;
122 }
123 
124 static const char *
log2str(Log level)125 log2str (Log level)
126 {
127   switch (level)
128     {
129       case Log::DEBUG:    return "liquidsfz::debug";
130       case Log::INFO:     return "liquidsfz::info";
131       case Log::WARNING:  return "liquidsfz::warning";
132       case Log::ERROR:    return "liquidsfz::error";
133       default:            return "***loglevel?***";
134     }
135 }
136 
137 void
logv(Log level,const char * format,va_list vargs) const138 Synth::logv (Log level, const char *format, va_list vargs) const
139 {
140   char buffer[1024];
141 
142   vsnprintf (buffer, sizeof (buffer), format, vargs);
143 
144   if (log_function_)
145     log_function_ (level, buffer);
146   else
147     fprintf (stderr, "[%s] %s", log2str (level), buffer);
148 }
149 
150 void
error(const char * format,...) const151 Synth::error (const char *format, ...) const
152 {
153   if (log_level_ <= Log::ERROR)
154     {
155       va_list ap;
156 
157       va_start (ap, format);
158       logv (Log::ERROR, format, ap);
159       va_end (ap);
160     }
161 }
162 
163 void
warning(const char * format,...) const164 Synth::warning (const char *format, ...) const
165 {
166   if (log_level_ <= Log::WARNING)
167     {
168       va_list ap;
169 
170       va_start (ap, format);
171       logv (Log::WARNING, format, ap);
172       va_end (ap);
173     }
174 }
175 
176 void
info(const char * format,...) const177 Synth::info (const char *format, ...) const
178 {
179   if (log_level_ <= Log::INFO)
180     {
181       va_list ap;
182 
183       va_start (ap, format);
184       logv (Log::INFO, format, ap);
185       va_end (ap);
186     }
187 }
188 
189 void
debug(const char * format,...) const190 Synth::debug (const char *format, ...) const
191 {
192   if (log_level_ <= Log::DEBUG)
193     {
194       va_list ap;
195 
196       va_start (ap, format);
197       logv (Log::DEBUG, format, ap);
198       va_end (ap);
199     }
200 }
201 
202 Global Synth::global_;
203 
204 }
205