// This is the main DLL file.
#include "stdafx.h"
#include "stock_buffer.h"
#include "Tags.h"
#include "VorbisEnc.h"
#define READ 1024
void VorbisEnc::IVorbisEnc::UploadChunk32(signed char* data, long sz)
{
float f_temp = (float)FIXED32_ONE;
int eos=0, ret;
//while(!eos){
long i = 0;
//long bytes=fread(readbuffer,1,READ*4,stdin); /* stereo hardwired here */
long bytes = sz;
char* readbuffer = (char*)data;
if(bytes == 0){
/* end of file. this can be done implicitly in the mainline,
but it's easier to see here in non-clever fashion.
Tell the library we're at end of stream so that it can handle
the last frame and mark end of stream in the output properly */
vorbis_analysis_wrote(&vd, 0);
}else{
/* data to encode */
/* expose the buffer to submit data */
//float **buffer=vorbis_analysis_buffer(&vd,1024);
float **buffer = vorbis_analysis_buffer(&vd, sz / (this->channels * 4));
/* uninterleave samples */
//TODO: any number of channels
//stereo
if(this->channels == 2)
{
for(i=0;i < bytes / 8; i++){
buffer[0][i] = (*(int*)(readbuffer+(i*8))) / f_temp;
buffer[1][i] = (*(int*)(readbuffer+(i*8 + 4))) / f_temp;
}
}
//mono
else if(this->channels == 1)
{
for(i=0;i < bytes / 4; i++)
buffer[0][i] = (*(int*)(readbuffer+(i*4))) / f_temp;
//buffer[0][i] = ((readbuffer[i*2+1] << 8)|
// (0x00ff & (int)readbuffer[i*2])) / 32768.f;
}
/* tell the library how much we actually submitted */
vorbis_analysis_wrote(&vd,i);
}
/* vorbis does some data preanalysis, then divvies up blocks for
more involved (potentially parallel) processing. Get a single
block for encoding now */
while(vorbis_analysis_blockout(&vd,&vb)==1){
/* analysis, assume we want to use bitrate management */
vorbis_analysis(&vb,NULL);
vorbis_bitrate_addblock(&vb);
while(vorbis_bitrate_flushpacket(&vd,&op)){
/* weld the packet into the bitstream */
ogg_stream_packetin(&os,&op);
/* write out pages (if any) */
while(!eos){
int result=ogg_stream_pageout(&os,&og);
if(result==0)break;
fwrite(og.header,1,og.header_len,this->_oggfile);
fwrite(og.body,1,og.body_len,this->_oggfile);
/* this could be set above, but for illustrative purposes, I do
it here (to show that vorbis does know where the stream ends) */
if(ogg_page_eos(&og))eos=1;
}
}
}
//}
}
void VorbisEnc::IVorbisEnc::UploadChunk(signed char* data, long sz)
{
int eos=0, ret;
//while(!eos){
long i = 0;
//long bytes=fread(readbuffer,1,READ*4,stdin); /* stereo hardwired here */
long bytes = sz;
char* readbuffer = (char*)data;
if(bytes == 0){
/* end of file. this can be done implicitly in the mainline,
but it's easier to see here in non-clever fashion.
Tell the library we're at end of stream so that it can handle
the last frame and mark end of stream in the output properly */
vorbis_analysis_wrote(&vd, 0);
}else{
/* data to encode */
/* expose the buffer to submit data */
//float **buffer=vorbis_analysis_buffer(&vd,1024);
float **buffer = vorbis_analysis_buffer(&vd, sz / (this->channels * 2));
/* uninterleave samples */
//TODO: any number of channels
//stereo
if(this->channels == 2)
{
for(i=0;i < bytes / 4; i++){
buffer[0][i] = ((readbuffer[i*4+1] << 8)|
(0x00ff & (int)readbuffer[i*4])) / 32768.f;
buffer[1][i] = ((readbuffer[i*4+3] << 8)|
(0x00ff & (int)readbuffer[i*4+2])) / 32768.f;
}
}
//mono
else if(this->channels == 1)
{
for(i=0;i < bytes / 2; i++)
buffer[0][i] = ((readbuffer[i*2+1] << 8)|
(0x00ff & (int)readbuffer[i*2])) / 32768.f;
}
/* tell the library how much we actually submitted */
vorbis_analysis_wrote(&vd,i);
}
/* vorbis does some data preanalysis, then divvies up blocks for
more involved (potentially parallel) processing. Get a single
block for encoding now */
while(vorbis_analysis_blockout(&vd,&vb)==1){
/* analysis, assume we want to use bitrate management */
vorbis_analysis(&vb,NULL);
vorbis_bitrate_addblock(&vb);
while(vorbis_bitrate_flushpacket(&vd,&op)){
/* weld the packet into the bitstream */
ogg_stream_packetin(&os,&op);
/* write out pages (if any) */
while(!eos){
int result=ogg_stream_pageout(&os,&og);
if(result==0)break;
fwrite(og.header,1,og.header_len,this->_oggfile);
fwrite(og.body,1,og.body_len,this->_oggfile);
/* this could be set above, but for illustrative purposes, I do
it here (to show that vorbis does know where the stream ends) */
if(ogg_page_eos(&og))eos=1;
}
}
}
//}
}
void VorbisEnc::IVorbisEnc::Close(void)
{
ogg_stream_clear(&this->os);
vorbis_block_clear(&this->vb);
vorbis_dsp_clear(&this->vd);
vorbis_comment_clear(&this->vc);
vorbis_info_clear(&this->vi);
fclose(this->_oggfile);
}
//2,44100,0.1
int VorbisEnc::IVorbisEnc::Initialise(char* stringFile, int channels, int rate, double q, Tag^ t)
{
//this->_oggfile = fopen(stringFile, "wb");
this->_oggfile = _wfopen((wchar_t*)stringFile, L"wb");
this->channels = channels;
if(!this->_oggfile)return 0;
int eos=0,ret;
int i, founddata;
vorbis_info_init(&this->vi);
if(q<10.0)
{
ret=vorbis_encode_init_vbr(&this->vi, channels, rate, q);
}else{
q = q * 1000;
ret = vorbis_encode_init(&this->vi, channels, rate, -1, q, -1);
}
if(ret)
return 0;
/* add a comment */
vorbis_comment_init(&this->vc);
if(t->track)
vorbis_comment_add_tag(&this->vc, "TITLE", t->track);
if(t->artist)
vorbis_comment_add_tag(&this->vc, "ARTIST", t->artist);
if(t->album)
vorbis_comment_add_tag(&this->vc, "ALBUM", t->album);
if(t->year)
vorbis_comment_add_tag(&this->vc, "DATE", t->year);
if(t->tracknum)
vorbis_comment_add_tag(&this->vc, "TRACKNUMBER", t->tracknum);
if(t->genre)
vorbis_comment_add_tag(&this->vc, "GENRE", t->genre);
if(t->pic)
{
vorbis_comment_add_tag(&this->vc, "COVERARTMIME", "image/jpeg");
vorbis_comment_add_tag(&this->vc, "COVERARTDESCRIPTION", "cover.jpg");
vorbis_comment_add_tag(&this->vc, "COVERART", t->pic);
}
if(t->publisher)
vorbis_comment_add_tag(&this->vc, "PUBLISHER", t->publisher);
if(t->comment)
vorbis_comment_add_tag(&this->vc, "COMMENT", t->comment);
vorbis_comment_add_tag(&this->vc, "ENCODER", "cerriun VorbisEnc library for .NET, please navigate to http://www.xiph.org/");
/* set up the analysis state and auxiliary encoding storage */
vorbis_analysis_init(&this->vd,&this->vi);
vorbis_block_init(&this->vd,&this->vb);
/* set up our packet->stream encoder */
/* pick a random serial number; that way we can more likely build
chained streams just by concatenation */
srand(time(NULL));
ogg_stream_init(&this->os,rand());
{
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
vorbis_analysis_headerout(&this->vd,&vc,&header,&header_comm,&header_code);
ogg_stream_packetin(&this->os,&header); /* automatically placed in its own
page */
ogg_stream_packetin(&this->os,&header_comm);
ogg_stream_packetin(&this->os,&header_code);
/* This ensures the actual
* audio data will start on a new page, as per spec
*/
while(!eos){
int result=ogg_stream_flush(&this->os,&this->og);
if(result==0)break;
fwrite(this->og.header,1,this->og.header_len,this->_oggfile);
fwrite(this->og.body,1,this->og.body_len,this->_oggfile);
}
return 1;
}
}