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