1 /**
2 * File name: audio_output.c
3 * Project: Geonkick (A kick synthesizer)
4 *
5 * Copyright (C) 2018 Iurie Nistor <http://iuriepage.wordpress.com>
6 *
7 * This file is part of Geonkick.
8 *
9 * GeonKick is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "audio_output.h"
25
26 enum geonkick_error
gkick_audio_output_create(struct gkick_audio_output ** audio_output,int sample_rate)27 gkick_audio_output_create(struct gkick_audio_output **audio_output, int sample_rate)
28 {
29 if (audio_output == NULL) {
30 gkick_log_error("wrong arguments");
31 return GEONKICK_ERROR;
32 }
33
34 *audio_output = (struct gkick_audio_output*)calloc(1, sizeof(struct gkick_audio_output));
35 if (*audio_output == NULL) {
36 gkick_log_error("can't allocate memory");
37 return GEONKICK_ERROR;
38 }
39 (*audio_output)->decay = -1;
40 (*audio_output)->play = false;
41 (*audio_output)->enabled = true;
42 (*audio_output)->muted = false;
43 (*audio_output)->solo = false;
44 (*audio_output)->channel = 0;
45 (*audio_output)->sample_rate = sample_rate;
46
47 gkick_buffer_new((struct gkick_buffer**)&(*audio_output)->updated_buffer,
48 (*audio_output)->sample_rate * GEONKICK_MAX_LENGTH);
49 if ((*audio_output)->updated_buffer == NULL) {
50 gkick_log_error("can't create updated buffer");
51 gkick_audio_output_free(audio_output);
52 return GEONKICK_ERROR;
53 }
54 gkick_buffer_set_size((struct gkick_buffer*)(*audio_output)->updated_buffer, 0);
55
56 gkick_buffer_new((struct gkick_buffer**)&(*audio_output)->playing_buffer,
57 (*audio_output)->sample_rate * GEONKICK_MAX_LENGTH);
58 if ((*audio_output)->playing_buffer == NULL) {
59 gkick_log_error("can't create playing buffer");
60 gkick_audio_output_free(audio_output);
61 return GEONKICK_ERROR;
62 }
63 gkick_buffer_set_size((struct gkick_buffer*)(*audio_output)->playing_buffer, 0);
64
65 if (pthread_mutex_init(&(*audio_output)->lock, NULL) != 0) {
66 gkick_log_error("error on init mutex");
67 gkick_audio_output_free(audio_output);
68 return GEONKICK_ERROR;
69 }
70
71 return GEONKICK_OK;
72 }
73
gkick_audio_output_free(struct gkick_audio_output ** audio_output)74 void gkick_audio_output_free(struct gkick_audio_output **audio_output)
75 {
76 if (audio_output != NULL && *audio_output != NULL) {
77 struct gkick_buffer *p = (struct gkick_buffer*)((*audio_output)->playing_buffer);
78 gkick_buffer_free(&p);
79 p = (struct gkick_buffer*)((*audio_output)->updated_buffer);
80 gkick_buffer_free(&p);
81 pthread_mutex_destroy(&(*audio_output)->lock);
82 free(*audio_output);
83 *audio_output = NULL;
84 }
85 }
86
87 enum geonkick_error
gkick_audio_output_key_pressed(struct gkick_audio_output * audio_output,struct gkick_note_info * key)88 gkick_audio_output_key_pressed(struct gkick_audio_output *audio_output,
89 struct gkick_note_info *key)
90 {
91 if (key->state == GKICK_KEY_STATE_PRESSED) {
92 audio_output->key = *key;
93 audio_output->is_play = true;
94 gkick_audio_output_swap_buffers(audio_output);
95 } else {
96 audio_output->decay = GEKICK_KEY_RELESE_DECAY_TIME;
97 audio_output->key.state = key->state;
98 }
99
100 return GEONKICK_OK;
101 }
102
103 enum geonkick_error
gkick_audio_output_play(struct gkick_audio_output * audio_output)104 gkick_audio_output_play(struct gkick_audio_output *audio_output)
105 {
106 audio_output->play = true;
107 return GEONKICK_OK;
108 }
109
110 gkick_real
gkick_audio_output_tune_factor(int note_number)111 gkick_audio_output_tune_factor(int note_number)
112 {
113 return exp2f((gkick_real)(note_number - 69) / 12.0f);
114 }
115
116 enum geonkick_error
gkick_audio_output_get_frame(struct gkick_audio_output * audio_output,gkick_real * val)117 gkick_audio_output_get_frame(struct gkick_audio_output *audio_output,
118 gkick_real *val)
119 {
120 int release_time = GEKICK_KEY_RELESE_DECAY_TIME;
121 gkick_real decay_val;
122
123 if (audio_output->play) {
124 struct gkick_note_info key;
125 key.channel = 1;
126 key.note_number = 69;
127 key.velocity = 127;
128 key.state = GKICK_KEY_STATE_PRESSED;
129 gkick_audio_output_key_pressed(audio_output, &key);
130 audio_output->play = false;
131 }
132
133 *val = 0;
134 if (audio_output->is_play) {
135 if (gkick_buffer_is_end((struct gkick_buffer*)audio_output->playing_buffer)) {
136 audio_output->is_play = false;
137 } else {
138 struct gkick_buffer *buff = (struct gkick_buffer*)audio_output->playing_buffer;
139 gkick_real factor = gkick_audio_output_tune_factor(audio_output->key.note_number);
140 if (audio_output->tune)
141 *val = gkick_buffer_stretch_get_next(buff, factor);
142 else
143 *val = gkick_buffer_get_next(buff);
144
145 if (gkick_buffer_size(buff) - gkick_buffer_index(buff) == GEKICK_KEY_RELESE_DECAY_TIME) {
146 audio_output->decay = GEKICK_KEY_RELESE_DECAY_TIME;
147 audio_output->key.state = GKICK_KEY_STATE_RELEASED;
148 }
149
150 if (audio_output->key.state == GKICK_KEY_STATE_RELEASED)
151 decay_val = - 1.0f * ((gkick_real)(release_time - audio_output->decay) / release_time) + 1.0;
152 else
153 decay_val = 1.0f;
154 *val *= decay_val * ((gkick_real)audio_output->key.velocity / 127);
155
156 if (audio_output->key.state == GKICK_KEY_STATE_RELEASED) {
157 audio_output->decay--;
158 if (audio_output->decay < 0)
159 audio_output->is_play = false;
160 }
161 }
162 }
163
164 *val *= (gkick_real)audio_output->limiter / 1000000;
165
166 return GEONKICK_OK;
167 }
168
gkick_audio_output_lock(struct gkick_audio_output * audio_output)169 void gkick_audio_output_lock(struct gkick_audio_output *audio_output)
170 {
171 if (audio_output != NULL)
172 pthread_mutex_lock(&audio_output->lock);
173 }
174
gkick_audio_output_unlock(struct gkick_audio_output * audio_output)175 void gkick_audio_output_unlock(struct gkick_audio_output *audio_output)
176 {
177 if (audio_output != NULL)
178 pthread_mutex_unlock(&audio_output->lock);
179 }
180
181 struct gkick_buffer*
gkick_audio_output_get_buffer(struct gkick_audio_output * audio_output)182 gkick_audio_output_get_buffer(struct gkick_audio_output *audio_output)
183 {
184 return (struct gkick_buffer*)audio_output->playing_buffer;
185 }
186
gkick_audio_output_swap_buffers(struct gkick_audio_output * audio_output)187 void gkick_audio_output_swap_buffers(struct gkick_audio_output *audio_output)
188 {
189 gkick_buffer_reset((struct gkick_buffer*)audio_output->playing_buffer);
190
191 /**
192 * Try lock. If succesfull, swap buffers. If not, continue with
193 * the current one to play until the next press of the key.
194 */
195 if (pthread_mutex_trylock(&audio_output->lock) == 0) {
196 /* Test if the updated buffer is full. Otherwise it means that it was not updated. */
197 if (gkick_buffer_size((struct gkick_buffer*)audio_output->updated_buffer) > 0
198 && gkick_buffer_is_end((struct gkick_buffer*)audio_output->updated_buffer)) {
199 char *buff = audio_output->updated_buffer;
200 audio_output->updated_buffer = audio_output->playing_buffer;
201 audio_output->playing_buffer = buff;
202 }
203 gkick_buffer_reset((struct gkick_buffer*)audio_output->playing_buffer);
204 gkick_audio_output_unlock(audio_output);
205 }
206 }
207
208 enum geonkick_error
gkick_audio_output_set_playing_key(struct gkick_audio_output * audio_output,signed char key)209 gkick_audio_output_set_playing_key(struct gkick_audio_output *audio_output, signed char key)
210 {
211 if (key < 21 || key > 108)
212 key = GEONKICK_ANY_KEY;
213 audio_output->playing_key = key;
214 return GEONKICK_OK;
215 }
216
217 enum geonkick_error
gkick_audio_output_get_playing_key(struct gkick_audio_output * audio_output,signed char * key)218 gkick_audio_output_get_playing_key(struct gkick_audio_output *audio_output, signed char *key)
219 {
220 *key = audio_output->playing_key;
221 return GEONKICK_OK;
222 }
223
224
gkick_audio_output_tune_output(struct gkick_audio_output * audio_output,bool tune)225 void gkick_audio_output_tune_output(struct gkick_audio_output *audio_output, bool tune)
226 {
227 audio_output->tune = tune;
228 }
229
gkick_audio_output_is_tune_output(struct gkick_audio_output * audio_output)230 bool gkick_audio_output_is_tune_output(struct gkick_audio_output *audio_output)
231 {
232 return audio_output->tune;
233 }
234
235 enum geonkick_error
gkick_audio_output_set_channel(struct gkick_audio_output * audio_output,size_t channel)236 gkick_audio_output_set_channel(struct gkick_audio_output *audio_output,
237 size_t channel)
238 {
239 audio_output->channel = channel;
240 return GEONKICK_OK;
241 }
242
243 enum geonkick_error
gkick_audio_output_get_channel(struct gkick_audio_output * audio_output,size_t * channel)244 gkick_audio_output_get_channel(struct gkick_audio_output *audio_output,
245 size_t *channel)
246 {
247 *channel = audio_output->channel;
248 return GEONKICK_OK;
249 }
250