-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwaveform.c
160 lines (127 loc) · 4.21 KB
/
waveform.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
#include<Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <groove/groove.h>
#include <limits.h>
typedef struct {
PyObject_HEAD
int size;
float *data;
float duration;
} Samples;
int getSoundPoints(Samples* soundPoints, char* in_file_path, int fps) {
float min_sample = -1.0f;
int samples_to_take = 635;
int frame_count = 0;
int frames_until_emit;
int emit_every;
//printf("Using libgroove v%s\n", groove_version());
groove_init();
groove_set_logging(GROOVE_LOG_QUIET);
struct GrooveFile *file = groove_file_open(in_file_path);
if (! file) {
fprintf(stderr, "Error opening input file: %s\n", in_file_path);
groove_finish();
return 1;
}
//float duration = groove_file_duration(file);
struct GroovePlaylist *playlist = groove_playlist_create();
struct GrooveSink *sink = groove_sink_create();
struct GrooveBuffer *buffer;
sink->audio_format.sample_rate = 44100;
sink->audio_format.channel_layout = GROOVE_CH_LAYOUT_MONO;
sink->audio_format.sample_fmt = GROOVE_SAMPLE_FMT_FLT;
if (groove_sink_attach(sink, playlist) < 0) {
fprintf(stderr, "error attaching sink\n");
return 1;
}
struct GroovePlaylistItem *item =
groove_playlist_insert(playlist, file, 1.0, 1.0,NULL);
// scan the song for the exact correct duration
while (groove_sink_buffer_get(sink, &buffer, 1) == GROOVE_BUFFER_YES) {
frame_count += buffer->frame_count;
groove_buffer_unref(buffer);
}
groove_playlist_seek(playlist, item, 0);
// Calculate best sample resolution for file
// duration * fps
// samples_to_take = ; // take sample every 125ms (at 8)
emit_every = frame_count / samples_to_take;
frames_until_emit = emit_every;
// Initialize vector
soundPoints->size = 0;
soundPoints->data = calloc(samples_to_take+1, sizeof(float));
soundPoints->duration = groove_file_duration(file);
int i;
while (groove_sink_buffer_get(sink, &buffer, 1) == GROOVE_BUFFER_YES) {
// process the buffer
for (i = 0; i < buffer->frame_count && soundPoints->size < samples_to_take;
i += 1, frames_until_emit -= 1)
{
if (frames_until_emit == 0) {
soundPoints->data[soundPoints->size++] = min_sample;
frames_until_emit = emit_every;
min_sample = -1.0f;
}
float *samples = (float *) buffer->data[0];
float sample = samples[i];
if (sample > min_sample) min_sample = sample;
}
groove_buffer_unref(buffer);
}
// emit the last column if necessary. This will have to run multiple times
// if the duration specified in the metadata is incorrect.
while (soundPoints->size < samples_to_take) {
soundPoints->data[soundPoints->size++] = 0.0f;
}
groove_sink_detach(sink);
groove_sink_destroy(sink);
groove_playlist_clear(playlist);
groove_file_close(file);
groove_playlist_destroy(playlist);
groove_finish();
return 0;
}
static PyObject* extractWaveform(PyObject* self, PyObject* args)
{
char* input;
if(!PyArg_ParseTuple(args, "s", &input)) {
return NULL;
}
Samples result;
int err = getSoundPoints(&result, input, 8);
if (err != 0){
return Py_BuildValue("i", err);
}
PyObject *pylist = PyTuple_New(result.size);
PyObject *item;
for (int i = 0; i < result.size-1; ++i)
{
item = Py_BuildValue("f",result.data[i]);
Py_INCREF(item);
PyTuple_SetItem(pylist, i, item);;
Py_DECREF(item);
}
return Py_BuildValue("bfO", result.size, result.duration, pylist);
}
static PyObject* version(PyObject* self)
{
return Py_BuildValue("s", "1.0");
}
static PyMethodDef wfMethods[] = {
{"extractWaveform", extractWaveform, METH_VARARGS, "returns the waveform sample from the audio file."},
{"version", (PyCFunction)version, METH_NOARGS, "returns the version."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef wfModule = {
PyModuleDef_HEAD_INIT,
"waveform",
"Waveform Module",
-1,
wfMethods
};
PyMODINIT_FUNC PyInit_waveform(void)
{
return PyModule_Create(&wfModule);
}