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