1 // vorbis 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 <string.h>
17 #include <stdlib.h>
18 #include <time.h>
19
20 #include "config.h"
21 #include "cfg.h"
22 #include "vorbis_encode.h"
23
vorbis_enc_init(vorbis_enc * vorbis)24 int vorbis_enc_init(vorbis_enc *vorbis)
25 {
26 int ret;
27
28 //TODO: add error handling
29 vorbis_info_init(&(vorbis->vi));
30
31 ret = vorbis_encode_init(&(vorbis->vi),
32 vorbis->channel,
33 vorbis->samplerate,
34 vorbis->bitrate*1000,
35 vorbis->bitrate*1000,
36 vorbis->bitrate*1000);
37 if(ret)
38 return ret;
39
40 vorbis_comment_init(&(vorbis->vc));
41 vorbis_comment_add_tag(&(vorbis->vc), "ENCODER", PACKAGE_STRING);
42 // vorbis_comment_add_tag(&(vorbis->vc), "TITLE", "Hello Song");
43
44 vorbis_analysis_init(&(vorbis->vd), &(vorbis->vi));
45 vorbis_block_init(&(vorbis->vd), &(vorbis->vb));
46
47 return 0;
48 }
49
50 //This function needs to be called before
51 //every connection
vorbis_enc_write_header(vorbis_enc * vorbis)52 void vorbis_enc_write_header(vorbis_enc *vorbis)
53 {
54 ogg_packet header;
55 ogg_packet header_comm;
56 ogg_packet header_code;
57
58 srand(time(NULL));
59 ogg_stream_init(&(vorbis->os), rand());
60
61 vorbis_analysis_headerout(&(vorbis->vd), &(vorbis->vc),
62 &header, &header_comm, &header_code);
63
64 ogg_stream_packetin(&(vorbis->os), &header);
65 ogg_stream_packetin(&(vorbis->os), &header_comm);
66 ogg_stream_packetin(&(vorbis->os), &header_code);
67 }
68
vorbis_enc_reinit(vorbis_enc * vorbis)69 int vorbis_enc_reinit(vorbis_enc *vorbis)
70 {
71 if(vorbis != NULL)
72 {
73 vorbis_enc_close(vorbis);
74 return vorbis_enc_init(vorbis);
75 }
76 return 1;
77 }
78
vorbis_enc_encode(vorbis_enc * vorbis,short * pcm_buf,char * enc_buf,int size)79 int vorbis_enc_encode(vorbis_enc *vorbis, short *pcm_buf, char *enc_buf, int size)
80 {
81 int i, result;
82 int eos = 0;
83 int w = 0;
84 float **vorbis_buf;
85
86 if(size == 0)
87 return 0;
88
89 /* This ensures the actual
90 * audio data will start on a new page, as per spec
91 */
92 result = ogg_stream_flush(&(vorbis->os), &(vorbis->og));
93 memcpy(enc_buf+w, vorbis->og.header, vorbis->og.header_len);
94 w += vorbis->og.header_len;
95 memcpy(enc_buf+w, vorbis->og.body, vorbis->og.body_len);
96 w += vorbis->og.body_len;
97
98 vorbis_buf = vorbis_analysis_buffer(&(vorbis->vd), size);
99
100 //deinterlace audio data and convert it from short to float
101 if(vorbis->channel == 2) // stereo
102 {
103 for(i = 0; i < size; i++)
104 {
105 vorbis_buf[0][i] = pcm_buf[i*2]/32768.f;
106 vorbis_buf[1][i] = pcm_buf[i*2+1]/32768.f;
107 }
108 }
109 else // mono
110 {
111 for(i = 0; i < size; i++)
112 {
113 vorbis_buf[0][i] = pcm_buf[i]/32768.f;
114 }
115 }
116
117 vorbis_analysis_wrote(&(vorbis->vd), size);
118
119 while(vorbis_analysis_blockout(&(vorbis->vd), &(vorbis->vb)) == 1)
120 {
121 vorbis_analysis(&(vorbis->vb),&(vorbis->op));
122 vorbis_bitrate_addblock(&(vorbis->vb));
123
124 while(vorbis_bitrate_flushpacket(&(vorbis->vd),&(vorbis->op)))
125 {
126 /* weld the packet into the bitstream */
127 ogg_stream_packetin(&(vorbis->os),&(vorbis->op));
128
129
130 /* write out pages (if any) */
131 while(!eos)
132 {
133 result = ogg_stream_pageout(&(vorbis->os), &(vorbis->og));
134 if(result == 0)
135 break;
136
137 memcpy(enc_buf+w, vorbis->og.header, vorbis->og.header_len);
138 w += vorbis->og.header_len;
139 memcpy(enc_buf+w, vorbis->og.body, vorbis->og.body_len);
140 w += vorbis->og.body_len;
141 eos = ogg_page_eos(&(vorbis->og));
142 }
143 }
144 }
145
146 return w;
147 }
148
vorbis_enc_close(vorbis_enc * vorbis)149 void vorbis_enc_close(vorbis_enc *vorbis)
150 {
151 ogg_stream_clear(&(vorbis->os));
152 vorbis_block_clear(&(vorbis->vb));
153 vorbis_dsp_clear(&(vorbis->vd));
154 vorbis_comment_clear(&(vorbis->vc));
155 vorbis_info_clear(&(vorbis->vi));
156 }
157