-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplayer.c
102 lines (81 loc) · 2.68 KB
/
player.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
#include "player.h"
#include "tone.h"
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <stdio.h>
#include <math.h>
static void secsleep (float ms);
static int note_freq (note n);
static int tune (int freq);
static void play_note (note n, int tempo, int c);
static void play_channel (channel *c, int tempo, int c_number);
static void *channel_thread_f (void *args);
int silent = 0;
int verbose = 0;
static void secsleep (float s) {
struct timespec req;
req.tv_sec = s;
req.tv_nsec = ((double) s - (double) req.tv_sec) * 1000000000;
nanosleep (&req, NULL);
}
static int note_freq (note n) {
const float C0 = 16.351597831287418;
const float base_exp = 1.0594630943592953;
int octave_mult = 1 << n.octave;
return octave_mult * (C0 * pow (base_exp, n.figure));
}
static int tune (int freq) {
const float magic = 0.013; /* May be different on your machine */
return magic * magic * freq * freq + freq;
}
static void play_note (note n, int tempo, int c) {
int freq = tune (note_freq (n));
float duration_s = n.duration / ((float) tempo / 60.);
float interval_s = duration_s / 20;
if (verbose) print_note (n);
if (!n.silence) {
tone (freq, duration_s - interval_s, 0x1 << c);
secsleep (interval_s);
}
else secsleep (duration_s);
}
static void play_channel (channel *c, int tempo, int c_number) {
for (note_cell *cell = c->first;
cell != NULL;
cell = cell->next) play_note (cell->n, tempo, c_number);
}
static void *channel_thread_f (void *arg) {
struct {
channel *c;
int tempo;
pthread_barrier_t *barrier;
int c_number;
} *args = arg;
pthread_barrier_wait ((args->barrier));
play_channel (args->c, args->tempo, args->c_number);
return NULL;
}
void play_song (song *s) {
pthread_t threads[8];
pthread_barrier_t barrier;
int n = s->n_ch;
struct {
channel *c;
int tempo;
pthread_barrier_t *barrier;
int c_number;
} th_args[32];
pthread_barrier_init (&barrier, NULL, n);
if (!silent) lpt_init ();
for (int i = 0; i < n; i++) {
th_args[i].c = s->channels[i];
th_args[i].tempo = s->tempo;
th_args[i].barrier = &barrier;
th_args[i].c_number = i;
pthread_create (threads + i, NULL,
channel_thread_f,
(void *) (th_args + i));
}
for (int i = 0; i < n; i++) pthread_join (threads[i], NULL);
}