Files
SingularityViewer/indra/llaudio/llvorbisdecode.cpp
Lirusaito 61beedd3d9 Changed style of comments with asterisks to avoid highlighting errors on //* with weak highlighters, change is to all files that could potentially break highlights
Most were needed, though some were just for possible problems with highlighting, should not affect performance whatsoever.
2012-01-09 05:40:03 -05:00

327 lines
7.2 KiB
C++

/**
* @file vorbisdecode.cpp
* @brief Vorbis decoding routine routine for Indra.
*
* $LicenseInfo:firstyear=2000&license=viewergpl$
*
* Copyright (c) 2000-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
#include "llerror.h"
#include "llmath.h"
#include "llvfile.h"
#if 0
size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource)
{
LLVFile *file = (LLVFile *)datasource;
if (size > 0 && file->read((U8*)ptr, size * nmemb)) /*Flawfinder: ignore*/
{
S32 read = file->getLastBytesRead();
return read / size; /*Flawfinder: ignore*/
}
else
{
return 0;
}
}
int vfs_seek(void *datasource, ogg_int64_t offset, int whence)
{
LLVFile *file = (LLVFile *)datasource;
// vfs has 31-bit files
if (offset > S32_MAX)
{
return -1;
}
S32 origin;
switch (whence) {
case SEEK_SET:
origin = 0;
break;
case SEEK_END:
origin = file->getSize();
break;
case SEEK_CUR:
origin = -1;
break;
default:
llerrs << "Invalid whence argument to vfs_seek" << llendl;
return -1;
}
if (file->seek((S32)offset, origin))
{
return 0;
}
else
{
return -1;
}
}
int vfs_close (void *datasource)
{
LLVFile *file = (LLVFile *)datasource;
delete file;
return 0;
}
long vfs_tell (void *datasource)
{
LLVFile *file = (LLVFile *)datasource;
return file->tell();
}
BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname)
{
ov_callbacks vfs_callbacks;
vfs_callbacks.read_func = vfs_read;
vfs_callbacks.seek_func = vfs_seek;
vfs_callbacks.close_func = vfs_close;
vfs_callbacks.tell_func = vfs_tell;
char pcmout[4096]; /*Flawfinder: ignore*/
unsigned char temp[64]; /*Flawfinder: ignore*/
LLVFile *in_vfile;
U32 data_length = 0;
llinfos << "Vorbis decode from vfile: " << in_uuid << llendl;
in_vfile = new LLVFile(vfs, in_uuid, LLAssetType::AT_SOUND);
if (! in_vfile->getSize())
{
llwarning("unable to open vorbis source vfile for reading",0);
return(FALSE);
}
// **********************************
LLAPRFile outfile ;
outfile.open(out_fname,LL_APR_WPB);
// **********************************
if (!outfile.getFileHandle())
{
llwarning("unable to open vorbis destination file for writing",0);
return(FALSE);
}
else
{
// write the .wav format header
//"RIFF"
temp[0] = 0x52;
temp[1] = 0x49;
temp[2] = 0x46;
temp[3] = 0x46;
// length = datalen + 36 (to be filled in later)
temp[4] = 0x00;
temp[5] = 0x00;
temp[6] = 0x00;
temp[7] = 0x00;
//"WAVE"
temp[8] = 0x57;
temp[9] = 0x41;
temp[10] = 0x56;
temp[11] = 0x45;
// "fmt "
temp[12] = 0x66;
temp[13] = 0x6D;
temp[14] = 0x74;
temp[15] = 0x20;
// chunk size = 16
temp[16] = 0x10;
temp[17] = 0x00;
temp[18] = 0x00;
temp[19] = 0x00;
// format (1 = PCM)
temp[20] = 0x01;
temp[21] = 0x00;
// number of channels
temp[22] = 0x01;
temp[23] = 0x00;
// samples per second
temp[24] = 0x44;
temp[25] = 0xAC;
temp[26] = 0x00;
temp[27] = 0x00;
// average bytes per second
temp[28] = 0x88;
temp[29] = 0x58;
temp[30] = 0x01;
temp[31] = 0x00;
// bytes to output at a single time
temp[32] = 0x02;
temp[33] = 0x00;
// 16 bits per sample
temp[34] = 0x10;
temp[35] = 0x00;
// "data"
temp[36] = 0x64;
temp[37] = 0x61;
temp[38] = 0x74;
temp[39] = 0x61;
// these are the length of the data chunk, to be filled in later
temp[40] = 0x00;
temp[41] = 0x00;
temp[42] = 0x00;
temp[43] = 0x00;
outfile.write(temp, 44);
}
OggVorbis_File vf;
int eof=0;
int current_section;
int r = ov_open_callbacks(in_vfile, &vf, NULL, 0, vfs_callbacks);
if(r < 0)
{
llwarns << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << in_uuid << llendl;
return(FALSE);
}
{
char **ptr=ov_comment(&vf,-1)->user_comments;
// vorbis_info *vi=ov_info(&vf,-1);
while(*ptr){
fprintf(stderr,"%s\n",*ptr);
++ptr;
}
// fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate);
// fprintf(stderr,"\nDecoded length: %ld samples\n", (long)ov_pcm_total(&vf,-1));
// fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor);
}
while(!eof){
long ret=ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,&current_section);
if (ret == 0) {
/* EOF */
eof=1;
// llinfos << "Vorbis EOF" << llendl;
} else if (ret < 0) {
/* error in the stream. Not a problem, just reporting it in
case we (the app) cares. In this case, we don't. */
llwarning("Error in vorbis stream",0);
break;
} else {
// llinfos << "Vorbis read " << ret << "bytes" << llendl;
/* we don't bother dealing with sample rate changes, etc, but.
you'll have to*/
data_length += outfile.write(pcmout, ret);
}
}
ov_clear(&vf);
// write "data" chunk length
outfile.seek(APR_SET,40);
outfile.write(&data_length,4);
// write overall "RIFF" length
data_length += 36;
outfile.seek(APR_SET,4);
outfile.write(&data_length,1*4);
// FUCK!!! Vorbis encode/decode messes up loop point transitions (pop)
// do a cheap-and-cheesy crossfade
S16 *samplep;
S32 i;
S32 fade_length;
fade_length = llmin((S32)128,(S32)(data_length-36)/8);
outfile.seek(APR_SET,44);
outfile.read(pcmout,2*fade_length); //read first 16 samples
samplep = (S16 *)pcmout;
for (i = 0 ;i < fade_length; i++)
{
*samplep++ = ((F32)*samplep * ((F32)i/(F32)fade_length));
}
outfile.seek(APR_SET,44);
outfile.write(pcmout,2*fade_length); //write back xfaded first 16 samples
outfile.seek(APR_END,-fade_length*2);
outfile.read(pcmout,2*fade_length); //read last 16 samples
samplep = (S16 *)pcmout;
for (i = fade_length-1 ; i >= 0; i--)
{
*samplep++ = ((F32)*samplep * ((F32)i/(F32)fade_length));
}
outfile.seek(SEEK_END,-fade_length*2);
outfile.write(pcmout,2*fade_length); //write back xfaded last 16 samples
// *******************
outfile.close();
// *******************
if ((36 == data_length) || (!(eof)))
{
llwarning("BAD Vorbis DECODE!, removing .wav!",0);
LLFile::remove(out_fname);
return (FALSE);
}
// fprintf(stderr,"Done.\n");
return(TRUE);
}
#endif