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