-
Notifications
You must be signed in to change notification settings - Fork 3
/
sequencer.c
160 lines (139 loc) · 5.06 KB
/
sequencer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*!
* Polyphonic synthesizer for microcontrollers. Sequencer code.
* (C) 2021 Luciano Martorella
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "sequencer.h"
#include "debug.h"
#include <stdlib.h>
#include <string.h>
/*! State used between `seq_play_stream` and `seq_feed_synth` */
static int frame_count;
static uint8_t voice_count;
static uint8_t (*new_frame_require)(struct seq_frame_t* frame);
void seq_set_stream_require_handler(uint8_t (*handler)(struct seq_frame_t* frame)) {
new_frame_require = handler;
}
/*! State of the sequencer compiler */
struct compiler_state_t {
/*! The synth used for simulation */
struct poly_synth_t* synth;
/*! The input channel map */
struct seq_frame_map_t* input_map;
/*! The output frame stream */
struct seq_frame_t* out_stream;
/*! The position of writing frame in the output stream */
int stream_position;
/*! The positions of every channel in the input channel map */
int* channel_positions;
};
/*! Feed the first free channel and copy the selected frame in the output stream */
static void seq_feed_channels(struct compiler_state_t* state) {
intptr_t mask = 1;
int voice_idx = 0;
for (int map_idx = 0; map_idx < state->input_map->channel_count; map_idx++) {
// Skip empty channels
const struct seq_frame_list_t* channel = &state->input_map->channels[map_idx];
if (channel->count > 0) {
if (state->channel_positions[voice_idx] < channel->count && (state->synth->enable & mask) == 0) {
// Feed data
struct seq_frame_t* frame = channel->frames + (state->channel_positions[voice_idx]++);
voice_wf_set(&state->synth->voice[voice_idx].wf, &frame->waveform_def);
adsr_config(&state->synth->voice[voice_idx].adsr, &frame->adsr_def);
state->synth->enable |= mask;
state->out_stream[state->stream_position++] = *frame;
// Don't overload the CPU with multiple frames per sample
// This will create minimum phase errors (of 1 sample period) but will keep the process real-time on slower CPUs
break;
}
mask <<= 1;
voice_idx++;
}
}
}
void seq_compile(struct seq_frame_map_t* map, struct seq_frame_t** frame_stream, int* frame_count, int* voice_count) {
int total_frame_count = 0;
// Skip empty channels
int valid_channel_count = 0;
for (int i = 0; i < map->channel_count; i++) {
if (map->channels[i].count > 0) {
valid_channel_count++;
total_frame_count += map->channels[i].count;
}
}
// Prepare output buffer, with total frame count
*frame_count = total_frame_count;
*voice_count = valid_channel_count;
*frame_stream = malloc(sizeof(struct seq_frame_t) * total_frame_count);
// Now play sequencer data, currently by channel, simulating the timing of the synth.
struct poly_synth_t synth;
struct voice_ch_t* poly_voice = malloc(sizeof(struct voice_ch_t) * valid_channel_count);
synth.voice = poly_voice;
synth.mute = 0;
synth.enable = 0;
struct compiler_state_t state;
state.channel_positions = malloc(sizeof(int) * valid_channel_count);
memset(state.channel_positions, 0, sizeof(int) * valid_channel_count);
state.input_map = map;
state.out_stream = *frame_stream;
state.stream_position = 0;
state.synth = &synth;
seq_feed_channels(&state);
while (synth.enable) {
poly_synth_next(&synth);
seq_feed_channels(&state);
}
free(poly_voice);
free(state.channel_positions);
}
int seq_play_stream(const struct seq_stream_header_t* stream_header, uint8_t _voice_count, struct poly_synth_t* synth) {
if (stream_header->voices > _voice_count) {
_DPRINTF("Not enough voices");
return 1;
}
if (stream_header->synth_frequency != synth_freq) {
_DPRINTF("Mismatching sampling frequency");
return 1;
}
frame_count = stream_header->frames;
voice_count = stream_header->voices;
// Disable all channels
synth->enable = 0;
return 0;
}
void seq_feed_synth(struct poly_synth_t* synth) {
uintptr_t mask = 1;
for (uint8_t i = 0; i < voice_count; i++, mask <<= 1) {
if ((synth->enable & mask) == 0) {
// Feed data
struct seq_frame_t frame;
if (!new_frame_require(&frame)) {
// End-of-stream
return;
}
voice_wf_set(&synth->voice[i].wf, &frame.waveform_def);
adsr_config(&synth->voice[i].adsr, &frame.adsr_def);
synth->enable |= mask;
// Don't overload the CPU with multiple frames per sample
// This will create minimum phase errors (of 1 sample period) but will keep the process real-time on slower CPUs
break;
}
}
}
void seq_free(struct seq_frame_t* frame_stream) {
free(frame_stream);
}