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