1 // flac encoding functions for butt
2 //
3 // Copyright 2007-2018 by Daniel Noethen.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or (at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include "flac_encode.h"
21
22 FLAC__uint64 g_bytes_written = 0;
23
24 static void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
25
26 static FLAC__StreamEncoderWriteStatus ogg_stream_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
27
28 uint8_t *g_enc_p = NULL;
29 uint8_t *g_hdr_p;
30 uint8_t g_hdr[1024];
31
32 int g_hdr_written;
33 int g_hdr_size = 0;
34
set_settings(flac_enc * flac)35 static bool set_settings(flac_enc *flac)
36 {
37 FLAC__bool ret = true;
38 ret &= FLAC__stream_encoder_set_verify(flac->encoder, false);
39 ret &= FLAC__stream_encoder_set_compression_level(flac->encoder, 5);
40 ret &= FLAC__stream_encoder_set_channels(flac->encoder, flac->channel);
41 ret &= FLAC__stream_encoder_set_bits_per_sample(flac->encoder, 16);
42 ret &= FLAC__stream_encoder_set_sample_rate(flac->encoder, flac->samplerate);
43 ret &= FLAC__stream_encoder_set_total_samples_estimate(flac->encoder, 0);
44 ret &= FLAC__stream_encoder_set_ogg_serial_number(flac->encoder, rand());
45
46 return ret;
47 }
48
49
50
inject_new_song_title(flac_enc * flac)51 static void inject_new_song_title(flac_enc *flac)
52 {
53 int comment_len;
54
55 if (flac->vorbis_comment.length > 0)
56 {
57 for (int i = 0; i < flac->vorbis_comment.data.vorbis_comment.num_comments; i++)
58 free(flac->vorbis_comment.data.vorbis_comment.comments[i].entry);
59
60 free(flac->vorbis_comment.data.vorbis_comment.comments);
61 memset(&flac->vorbis_comment, 0, sizeof(FLAC__StreamMetadata));
62 }
63
64 comment_len = strlen(flac->song_title);
65
66 flac->vorbis_comment.is_last = true;
67 flac->vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
68 flac->vorbis_comment.length = 3*sizeof(uint32_t) + comment_len; // size of data field with ".length" and ".num_comments" variables included
69 flac->vorbis_comment.data.vorbis_comment.vendor_string.length = 0;
70 flac->vorbis_comment.data.vorbis_comment.vendor_string.entry = 0;
71 flac->vorbis_comment.data.vorbis_comment.num_comments = 1;
72
73 flac->vorbis_comment.data.vorbis_comment.comments =
74 (FLAC__StreamMetadata_VorbisComment_Entry*)malloc(flac->vorbis_comment.data.vorbis_comment.num_comments *
75 sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
76
77 flac->vorbis_comment.data.vorbis_comment.comments[0].length = comment_len;
78 flac->vorbis_comment.data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc(comment_len+1);
79
80 memcpy(flac->vorbis_comment.data.vorbis_comment.comments[0].entry, flac->song_title, comment_len+1);
81 }
82
83
flac_enc_init(flac_enc * flac)84 int flac_enc_init(flac_enc *flac)
85 {
86 FLAC__bool ret = true;
87
88 if((flac->encoder = FLAC__stream_encoder_new()) == NULL)
89 {
90 printf("ERROR: allocating encoder\n");
91 return 1;
92 }
93 memset(&flac->vorbis_comment, 0, sizeof(FLAC__StreamMetadata));
94
95
96 if (flac->enc_type == FLAC_ENC_TYPE_STREAM)
97 ret = flac_enc_init_ogg_stream(flac);
98
99 if (ret == true)
100 {
101 flac->state = FLAC_STATE_OK;
102 return 0;
103 }
104 else
105 return 1;
106 }
107
108
flac_enc_init_FILE(flac_enc * flac,FILE * fout)109 int flac_enc_init_FILE(flac_enc *flac, FILE *fout)
110 {
111 FLAC__StreamEncoderInitStatus init_status;
112
113 set_settings(flac);
114
115 init_status = FLAC__stream_encoder_init_FILE(flac->encoder, fout, progress_callback, /*client_data=*/NULL);
116 if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
117 {
118 fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
119 return 1;
120 }
121
122 return 0;
123 }
124
flac_enc_init_ogg_stream(flac_enc * flac)125 FLAC__bool flac_enc_init_ogg_stream(flac_enc *flac)
126 {
127 FLAC__StreamEncoderInitStatus init_status;
128
129 g_hdr_written = 0;
130 g_hdr_size = 0;
131 g_hdr_p = g_hdr;
132
133 set_settings(flac);
134
135 if (flac->state == FLAC_STATE_UPDATE_META_DATA)
136 {
137 inject_new_song_title(flac);
138 FLAC__StreamMetadata *comment_pointer = &flac->vorbis_comment;
139 FLAC__stream_encoder_set_metadata(flac->encoder, &comment_pointer, 1);
140 flac->state = FLAC_STATE_OK;
141 }
142
143 init_status = FLAC__stream_encoder_init_ogg_stream(flac->encoder, NULL, ogg_stream_callback, NULL, NULL, NULL, NULL);
144 if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
145 {
146 fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
147 return false;
148 }
149
150 flac->state = FLAC_STATE_OK;
151
152 return true;
153 }
154
155
flac_update_song_title(flac_enc * flac,char * song_title)156 void flac_update_song_title(flac_enc *flac, char *song_title)
157 {
158 snprintf(flac->song_title, sizeof(flac->song_title), "TITLE=%s", song_title);
159 flac->state = FLAC_STATE_NEW_SONG_AVAILABLE;
160 }
161
flac_set_initial_song_title(flac_enc * flac,char * song_title)162 void flac_set_initial_song_title(flac_enc *flac, char *song_title)
163 {
164
165 snprintf(flac->song_title, sizeof(flac->song_title), "TITLE=%s", song_title);
166 flac->state = FLAC_STATE_UPDATE_META_DATA;
167 flac_enc_reinit(flac);
168
169 }
170
171
flac_enc_encode(flac_enc * flac,short * pcm_buf,int samples_per_chan,int channel)172 int flac_enc_encode(flac_enc *flac, short *pcm_buf, int samples_per_chan, int channel)
173 {
174 int i;
175 int samples_left;
176 int chunk_size;
177 int pcm_32[8192];
178
179 int samples_written = 0;
180
181 chunk_size = 2048;
182 if (chunk_size > samples_per_chan)
183 chunk_size = samples_per_chan;
184
185 samples_left = samples_per_chan;
186
187 while(samples_left > 0)
188 {
189 // Convert 16bit samples to 32bit samples
190 for(i = 0; i < chunk_size * channel; i++)
191 pcm_32[i] = (int)pcm_buf[i+samples_written];
192
193 FLAC__stream_encoder_process_interleaved(flac->encoder, pcm_32, chunk_size);
194
195 samples_written += chunk_size*channel;
196 samples_left -= chunk_size;
197
198 if(samples_left < chunk_size)
199 chunk_size = samples_left;
200 }
201
202 return 0;
203 }
204
flac_enc_encode_stream(flac_enc * flac,short * pcm_buf,uint8_t * enc_buf,int samples_per_chan,int channel,int new_stream)205 int flac_enc_encode_stream(flac_enc *flac, short *pcm_buf, uint8_t *enc_buf, int samples_per_chan, int channel, int new_stream)
206 {
207 int i;
208 int samples_left;
209 int chunk_size;
210 int bytes_written;
211 int pcm_32[8192];
212
213 g_enc_p = enc_buf;
214
215 if (g_hdr_written == 0)
216 {
217 memcpy(g_enc_p, g_hdr, g_hdr_size);
218 g_enc_p += g_hdr_size;
219 g_hdr_written = 1;
220 }
221
222 int samples_written = 0;
223
224 chunk_size = 2048;
225 if (chunk_size > samples_per_chan)
226 chunk_size = samples_per_chan;
227
228 samples_left = samples_per_chan;
229
230
231 while (samples_left > 0)
232 {
233 // Convert 16bit samples to 32bit samples
234 for(i = 0; i < chunk_size * channel; i++)
235 pcm_32[i] = (int)pcm_buf[i+samples_written];
236
237 FLAC__stream_encoder_process_interleaved(flac->encoder, pcm_32, chunk_size);
238
239 samples_written += chunk_size*channel;
240 samples_left -= chunk_size;
241
242 if(samples_left < chunk_size)
243 chunk_size = samples_left;
244 }
245
246 if (flac->state == FLAC_STATE_NEW_SONG_AVAILABLE)
247 {
248 FLAC__stream_encoder_finish(flac->encoder);
249 flac->state = FLAC_STATE_UPDATE_META_DATA;
250 }
251
252 bytes_written = (int)(g_enc_p - enc_buf);
253
254 return bytes_written;
255 }
256
flac_enc_reinit(flac_enc * flac)257 int flac_enc_reinit(flac_enc *flac)
258 {
259 flac_enc_close(flac);
260 return flac_enc_init(flac);
261 }
262
flac_enc_close(flac_enc * flac)263 void flac_enc_close(flac_enc *flac)
264 {
265 if(flac->encoder != NULL)
266 {
267 FLAC__stream_encoder_delete(flac->encoder);
268 }
269
270 flac->encoder = NULL;
271 }
272
273
progress_callback(const FLAC__StreamEncoder * encoder,FLAC__uint64 bytes_written,FLAC__uint64 samples_written,unsigned frames_written,unsigned total_frames_estimate,void * client_data)274 void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
275 {
276 g_bytes_written = bytes_written;
277 }
278
ogg_stream_callback(const FLAC__StreamEncoder * encoder,const FLAC__byte buffer[],size_t bytes,unsigned samples,unsigned current_frame,void * client_data)279 FLAC__StreamEncoderWriteStatus ogg_stream_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
280 {
281
282 if (current_frame == 0)
283 {
284 // assemble header
285 memcpy(g_hdr_p, buffer, bytes);
286 g_hdr_p += bytes;
287 g_hdr_size += bytes;
288 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
289 }
290
291 if (g_enc_p != NULL)
292 {
293 memcpy(g_enc_p, buffer, bytes);
294 g_enc_p += bytes;
295 }
296
297 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
298 }
299
flac_enc_get_bytes_written(void)300 FLAC__uint64 flac_enc_get_bytes_written(void)
301 {
302 return g_bytes_written;
303 }
304