This repository has been archived by the owner on Apr 1, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy paths_sin.c
141 lines (129 loc) · 4.54 KB
/
s_sin.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
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef DATS_DETECT_MEM_LEAK
#include "memory-leak-detector/leak_detector.h"
#endif
#include "synth.h"
/* clang-format off */
static DSOption options[] = {
{DSOPTION_FLOAT, "vibrato_frequency", "Vibrato frequency", {.floatv = 0}},
{DSOPTION_FLOAT, "vibrato_magnitude", "Vibrato magnitude", {.floatv = 0}},
{DSOPTION_INT, "attack_type", "Attack type (linear=0, exponential=1)", {.intv = 0}},
{DSOPTION_INT, "decay_type", "Decay type (linear=0, exponential=1)", {.intv = 0}},
{DSOPTION_INT, "sustain_type", "Sustain type (linear=0, exponential=1)", {.intv = 0}},
{DSOPTION_INT, "release_type", "Release type (linear=0, exponential=1)", {.intv = 0}},
{DSOPTION_FLOAT, "attack_exp_coeff", "Attack exponential coefficiant", {.floatv = 0.0}},
{DSOPTION_FLOAT, "decay_exp_coeff", "Attack exponential coefficiant", {.floatv = 0.0}},
{DSOPTION_FLOAT, "sustain_exp_coeff", "Attack exponential coefficiant", {.floatv = 0.0}},
{DSOPTION_FLOAT, "release_exp_coeff", "Decay exponential coefficiant", {.floatv = 0.0}},
/*{DSOPTION_INT, "attack_s", "Attack ending in samples", {.intv = 0}},
{DSOPTION_INT, "decay_s", "Decay begin in samples", {.intv= 0}},*/
{.option_name = NULL}
};
/* clang-format on */
static void free_string_options(void) {
for (int i = 0; options[i].option_name != NULL; i++) {
if (options[i].type != DSOPTION_STRING) {
options[i].value.intv = 0;
options[i].value.floatv = 0.0;
continue;
}
free(options[i].value.strv);
}
}
static double linear_attack(double x, double n) { return x / n; }
static double linear_release(double x, double n) { return x / n; }
static double exponential_attack(double x, double n) { return pow(M_E, x - n); }
static double exponential_release(double x, double n) {
return pow(M_E, (-x - n) + 1.0);
}
static pcm16_t *synth(const symrec_t *staff) {
double (*attack_ret)(double, double) = NULL;
double (*release_ret)(double, double) = NULL;
switch (options[2].value.intv) {
case 0:
attack_ret = linear_attack;
break;
case 1:
attack_ret = exponential_attack;
break;
default:
fprintf(stderr, "unknown attack type: %d\n", options[2].value.intv);
return NULL;
}
switch (options[5].value.intv) {
case 0:
release_ret = linear_release;
break;
case 1:
release_ret = exponential_release;
break;
default:
fprintf(stderr, "unknown attack type: %d\n", options[5].value.intv);
return NULL;
}
int16_t *pcm = calloc(sizeof(int16_t), (size_t)staff->value.staff.numsamples);
pcm16_t *pcm_ctx = malloc(sizeof(pcm16_t));
if (pcm_ctx == NULL || pcm == NULL)
return NULL;
uint32_t total = 0;
for (nr_t *n = staff->value.staff.nr; n != NULL; n = n->next) {
if (n->type == SYM_NOTE) {
for (note_t *nn = n->note; nn != NULL; nn = nn->next) {
for (uint32_t i = 0; i < nn->duration; i++) {
double sample1 =
((double)nn->volume *
sin(2.0 * M_PI *
(nn->frequency + sin(2.0 * M_PI * options[0].value.floatv *
(double)i / 44100.0) *
options[1].value.floatv) *
(double)i / 44100.0));
pcm[total + i] +=
(int16_t)
/* simple linear attack and linear decay filter */
(double)sample1 *
(i < (uint32_t)nn->attack
? attack_ret((double)i, nn->attack)
: (i > nn->duration - (uint32_t)nn->release
? release_ret(-(double)i + nn->duration, nn->release)
: 1.0));
}
}
}
total += n->length;
if ((total % 44100) < 1000) {
printf("\r[s_sin] %d/%d", total, staff->value.staff.numsamples);
fflush(stdout);
}
}
putchar('\n');
for (DSOption *ctx = options; ctx->option_name != NULL; ctx++) {
printf("[s_sin] %s ", ctx->option_name);
switch (ctx->type) {
case DSOPTION_FLOAT:
printf("%f", ctx->value.floatv);
break;
case DSOPTION_INT:
printf("%d", ctx->value.intv);
break;
case DSOPTION_STRING:
printf("%s", ctx->value.strv != NULL ? ctx->value.strv : " ");
break;
}
putchar('\n');
}
pcm_ctx->numsamples = staff->value.staff.numsamples;
pcm_ctx->pcm = pcm;
pcm_ctx->next = NULL;
free_string_options();
return pcm_ctx;
}
/* clang-format off */
DSSynth ss_sin = {
.name = "sin",
.description = "A sine wave synth",
.options = options,
.synth = &synth
};
/* clang-format on */