X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/e775f23a10c4ba37fc1a762299f52cd0d71593b7:/interpretor/libsndfile-1.0.25/src/ogg_vorbis.c..f1f94803668061f90a5ce88bf06ee72bba8e41a5:/interpretor/lib/src/libsndfile-1.0.25/src/static/gitweb.css diff --git a/interpretor/libsndfile-1.0.25/src/ogg_vorbis.c b/interpretor/libsndfile-1.0.25/src/ogg_vorbis.c deleted file mode 100644 index 99223cd..0000000 --- a/interpretor/libsndfile-1.0.25/src/ogg_vorbis.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* -** Copyright (C) 2002-2011 Erik de Castro Lopo -** Copyright (C) 2002-2005 Michael Smith -** Copyright (C) 2007 John ffitch -** -** This program is free software ; you can redistribute it and/or modify -** it under the terms of the GNU Lesser General Public License as published by -** the Free Software Foundation ; either version 2.1 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY ; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU Lesser General Public License for more details. -** -** You should have received a copy of the GNU Lesser General Public License -** along with this program ; if not, write to the Free Software -** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* -** Much of this code is based on the examples in libvorbis from the -** XIPHOPHORUS Company http://www.xiph.org/ which has a BSD-style Licence -** Copyright (c) 2002, Xiph.org Foundation -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** - Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** -** - Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** -** - Neither the name of the Xiph.org Foundation nor the names of its -** contributors may be used to endorse or promote products derived from -** this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION -** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE, -** DATA, OR PROFITS ; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "sfconfig.h" - -#include -#include -#include -#include -#include -#include - -#if HAVE_UNISTD_H -#include -#endif - -#include "sndfile.h" -#include "sfendian.h" -#include "common.h" - -#if HAVE_EXTERNAL_LIBS - -#include -#include -#include - -#include "ogg.h" - -typedef int convert_func (int, void *, int, int, float **) ; - -static int vorbis_read_header (SF_PRIVATE *psf, int log_data) ; -static int vorbis_write_header (SF_PRIVATE *psf, int calc_length) ; -static int vorbis_close (SF_PRIVATE *psf) ; -static int vorbis_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; -static sf_count_t vorbis_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; -static sf_count_t vorbis_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; -static sf_count_t vorbis_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; -static sf_count_t vorbis_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; -static sf_count_t vorbis_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; -static sf_count_t vorbis_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; -static sf_count_t vorbis_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; -static sf_count_t vorbis_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; -static sf_count_t vorbis_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; -static sf_count_t vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) ; -static sf_count_t vorbis_length (SF_PRIVATE *psf) ; - -typedef struct -{ int id ; - const char *name ; -} STR_PAIRS ; - -static STR_PAIRS vorbis_metatypes [] = -{ { SF_STR_TITLE, "Title" }, - { SF_STR_COPYRIGHT, "Copyright" }, - { SF_STR_SOFTWARE, "Software" }, - { SF_STR_ARTIST, "Artist" }, - { SF_STR_COMMENT, "Comment" }, - { SF_STR_DATE, "Date" }, - { SF_STR_ALBUM, "Album" }, - { SF_STR_LICENSE, "License" }, -} ; - -typedef struct -{ /* Count current location */ - sf_count_t loc ; - /* Struct that stores all the static vorbis bitstream settings */ - vorbis_info vinfo ; - /* Struct that stores all the bitstream user comments */ - vorbis_comment vcomment ; - /* Ventral working state for the packet->PCM decoder */ - vorbis_dsp_state vdsp ; - /* Local working space for packet->PCM decode */ - vorbis_block vblock ; - - /* Encoding quality in range [0.0, 1.0]. */ - double quality ; -} VORBIS_PRIVATE ; - -static int -vorbis_read_header (SF_PRIVATE *psf, int log_data) -{ - OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; - VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - char *buffer ; - int bytes ; - int i, nn ; - - odata->eos = 0 ; - - /* Weird stuff happens if these aren't called. */ - ogg_stream_reset (&odata->ostream) ; - ogg_sync_reset (&odata->osync) ; - - /* - ** Grab some data at the head of the stream. We want the first page - ** (which is guaranteed to be small and only contain the Vorbis - ** stream initial header) We need the first page to get the stream - ** serialno. - */ - - /* Expose the buffer */ - buffer = ogg_sync_buffer (&odata->osync, 4096L) ; - - /* Grab the part of the header that has already been read. */ - memcpy (buffer, psf->header, psf->headindex) ; - bytes = psf->headindex ; - - /* Submit a 4k block to libvorbis' Ogg layer */ - bytes += psf_fread (buffer + psf->headindex, 1, 4096 - psf->headindex, psf) ; - ogg_sync_wrote (&odata->osync, bytes) ; - - /* Get the first page. */ - if ((nn = ogg_sync_pageout (&odata->osync, &odata->opage)) != 1) - { - /* Have we simply run out of data? If so, we're done. */ - if (bytes < 4096) - return 0 ; - - /* Error case. Must not be Vorbis data */ - psf_log_printf (psf, "Input does not appear to be an Ogg bitstream.\n") ; - return SFE_MALFORMED_FILE ; - } ; - - /* - ** Get the serial number and set up the rest of decode. - ** Serialno first ; use it to set up a logical stream. - */ - ogg_stream_clear (&odata->ostream) ; - ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ; - - if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0) - { /* Error ; stream version mismatch perhaps. */ - psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; - return SFE_MALFORMED_FILE ; - } ; - - if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1) - { /* No page? must not be vorbis. */ - psf_log_printf (psf, "Error reading initial header packet.\n") ; - return SFE_MALFORMED_FILE ; - } ; - - /* - ** This function (vorbis_read_header) gets called multiple times, so the OGG - ** and vorbis structs have to be cleared every time we pass through to - ** prevent memory leaks. - */ - vorbis_block_clear (&vdata->vblock) ; - vorbis_dsp_clear (&vdata->vdsp) ; - vorbis_comment_clear (&vdata->vcomment) ; - vorbis_info_clear (&vdata->vinfo) ; - - /* - ** Extract the initial header from the first page and verify that the - ** Ogg bitstream is in fact Vorbis data. - ** - ** I handle the initial header first instead of just having the code - ** read all three Vorbis headers at once because reading the initial - ** header is an easy way to identify a Vorbis bitstream and it's - ** useful to see that functionality seperated out. - */ - vorbis_info_init (&vdata->vinfo) ; - vorbis_comment_init (&vdata->vcomment) ; - - if (vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) < 0) - { /* Error case ; not a vorbis header. */ - psf_log_printf (psf, "Found Vorbis in stream header, but vorbis_synthesis_headerin failed.\n") ; - return SFE_MALFORMED_FILE ; - } ; - - /* - ** Common Ogg metadata fields? - ** TITLE, VERSION, ALBUM, TRACKNUMBER, ARTIST, PERFORMER, COPYRIGHT, LICENSE, - ** ORGANIZATION, DESCRIPTION, GENRE, DATE, LOCATION, CONTACT, ISRC, - */ - - if (log_data) - { int k ; - - for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) - { char *dd ; - - dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ; - if (dd == NULL) - continue ; - psf_store_string (psf, vorbis_metatypes [k].id, dd) ; - } ; - } ; - - /* - ** At this point, we're sure we're Vorbis. We've set up the logical (Ogg) - ** bitstream decoder. Get the comment and codebook headers and set up the - ** Vorbis decoder. - ** - ** The next two packets in order are the comment and codebook headers. - ** They're likely large and may span multiple pages. Thus we reead - ** and submit data until we get our two pacakets, watching that no - ** pages are missing. If a page is missing, error out ; losing a - ** header page is the only place where missing data is fatal. - */ - - i = 0 ; /* Count of number of packets read */ - while (i < 2) - { int result = ogg_sync_pageout (&odata->osync, &odata->opage) ; - if (result == 0) - { /* Need more data */ - buffer = ogg_sync_buffer (&odata->osync, 4096) ; - bytes = psf_fread (buffer, 1, 4096, psf) ; - - if (bytes == 0 && i < 2) - { psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ; - return SFE_MALFORMED_FILE ; - } ; - nn = ogg_sync_wrote (&odata->osync, bytes) ; - } - else if (result == 1) - { /* - ** Don't complain about missing or corrupt data yet. We'll - ** catch it at the packet output phase. - ** - ** We can ignore any errors here as they'll also become apparent - ** at packetout. - */ - nn = ogg_stream_pagein (&odata->ostream, &odata->opage) ; - while (i < 2) - { result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ; - if (result == 0) - break ; - if (result < 0) - { /* Uh oh ; data at some point was corrupted or missing! - ** We can't tolerate that in a header. Die. */ - psf_log_printf (psf, "Corrupt secondary header. Exiting.\n") ; - return SFE_MALFORMED_FILE ; - } ; - - vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) ; - i++ ; - } ; - } ; - } ; - - if (log_data) - { int printed_metadata_msg = 0 ; - int k ; - - psf_log_printf (psf, "Bitstream is %d channel, %D Hz\n", vdata->vinfo.channels, vdata->vinfo.rate) ; - psf_log_printf (psf, "Encoded by : %s\n", vdata->vcomment.vendor) ; - - /* Throw the comments plus a few lines about the bitstream we're decoding. */ - for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++) - { char *dd ; - - dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ; - if (dd == NULL) - continue ; - - if (printed_metadata_msg == 0) - { psf_log_printf (psf, "Metadata :\n") ; - printed_metadata_msg = 1 ; - } ; - - psf_store_string (psf, vorbis_metatypes [k].id, dd) ; - psf_log_printf (psf, " %-10s : %s\n", vorbis_metatypes [k].name, dd) ; - } ; - - psf_log_printf (psf, "End\n") ; - } ; - - psf->sf.samplerate = vdata->vinfo.rate ; - psf->sf.channels = vdata->vinfo.channels ; - psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; - - /* OK, got and parsed all three headers. Initialize the Vorbis - ** packet->PCM decoder. - ** Central decode state. */ - vorbis_synthesis_init (&vdata->vdsp, &vdata->vinfo) ; - - /* Local state for most of the decode so multiple block decodes can - ** proceed in parallel. We could init multiple vorbis_block structures - ** for vd here. */ - vorbis_block_init (&vdata->vdsp, &vdata->vblock) ; - - vdata->loc = 0 ; - - return 0 ; -} /* vorbis_read_header */ - -static int -vorbis_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) -{ - OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; - VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - int k, ret ; - - vorbis_info_init (&vdata->vinfo) ; - - /* The style of encoding should be selectable here, VBR quality mode. */ - ret = vorbis_encode_init_vbr (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, vdata->quality) ; - -#if 0 - ret = vorbis_encode_init (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, -1, 128000, -1) ; /* average bitrate mode */ - ret = ( vorbis_encode_setup_managed (&vdata->vinfo, psf->sf.channels, - psf->sf.samplerate, -1, 128000, -1) || - vorbis_encode_ctl (&vdata->vinfo, OV_ECTL_RATEMANAGE_AVG, NULL) || - vorbis_encode_setup_init (&vdata->vinfo)) ; -#endif - if (ret) - return SFE_BAD_OPEN_FORMAT ; - - vdata->loc = 0 ; - - /* add a comment */ - vorbis_comment_init (&vdata->vcomment) ; - - vorbis_comment_add_tag (&vdata->vcomment, "ENCODER", "libsndfile") ; - for (k = 0 ; k < SF_MAX_STRINGS ; k++) - { const char * name ; - - if (psf->strings [k].type == 0) - break ; - - switch (psf->strings [k].type) - { case SF_STR_TITLE : name = "TITLE" ; break ; - case SF_STR_COPYRIGHT : name = "COPYRIGHT" ; break ; - case SF_STR_SOFTWARE : name = "SOFTWARE" ; break ; - case SF_STR_ARTIST : name = "ARTIST" ; break ; - case SF_STR_COMMENT : name = "COMMENT" ; break ; - case SF_STR_DATE : name = "DATE" ; break ; - case SF_STR_ALBUM : name = "ALBUM" ; break ; - case SF_STR_LICENSE : name = "LICENSE" ; break ; - default : continue ; - } ; - - vorbis_comment_add_tag (&vdata->vcomment, name, psf->strings [k].str) ; - } ; - - /* set up the analysis state and auxiliary encoding storage */ - vorbis_analysis_init (&vdata->vdsp, &vdata->vinfo) ; - vorbis_block_init (&vdata->vdsp, &vdata->vblock) ; - - /* - ** Set up our packet->stream encoder. - ** Pick a random serial number ; that way we can more likely build - ** chained streams just by concatenation. - */ - - ogg_stream_init (&odata->ostream, psf_rand_int32 ()) ; - - /* Vorbis streams begin with three headers ; the initial header (with - most of the codec setup parameters) which is mandated by the Ogg - bitstream spec. The second header holds any comment fields. The - third header holds the bitstream codebook. We merely need to - make the headers, then pass them to libvorbis one at a time ; - libvorbis handles the additional Ogg bitstream constraints */ - - { ogg_packet header ; - ogg_packet header_comm ; - ogg_packet header_code ; - int result ; - - vorbis_analysis_headerout (&vdata->vdsp, &vdata->vcomment, &header, &header_comm, &header_code) ; - ogg_stream_packetin (&odata->ostream, &header) ; /* automatically placed in its own page */ - ogg_stream_packetin (&odata->ostream, &header_comm) ; - ogg_stream_packetin (&odata->ostream, &header_code) ; - - /* This ensures the actual - * audio data will start on a new page, as per spec - */ - while ((result = ogg_stream_flush (&odata->ostream, &odata->opage)) != 0) - { psf_fwrite (odata->opage.header, 1, odata->opage.header_len, psf) ; - psf_fwrite (odata->opage.body, 1, odata->opage.body_len, psf) ; - } ; - } - - return 0 ; -} /* vorbis_write_header */ - -static int -vorbis_close (SF_PRIVATE *psf) -{ OGG_PRIVATE* odata = psf->container_data ; - VORBIS_PRIVATE *vdata = psf->codec_data ; - - if (odata == NULL || vdata == NULL) - return 0 ; - - /* Clean up this logical bitstream ; before exit we shuld see if we're - ** followed by another [chained]. */ - - if (psf->file.mode == SFM_WRITE) - { - if (psf->write_current <= 0) - vorbis_write_header (psf, 0) ; - - vorbis_analysis_wrote (&vdata->vdsp, 0) ; - while (vorbis_analysis_blockout (&vdata->vdsp, &vdata->vblock) == 1) - { - - /* analysis, assume we want to use bitrate management */ - vorbis_analysis (&vdata->vblock, NULL) ; - vorbis_bitrate_addblock (&vdata->vblock) ; - - while (vorbis_bitrate_flushpacket (&vdata->vdsp, &odata->opacket)) - { /* weld the packet into the bitstream */ - ogg_stream_packetin (&odata->ostream, &odata->opacket) ; - - /* write out pages (if any) */ - while (!odata->eos) - { int result = ogg_stream_pageout (&odata->ostream, &odata->opage) ; - if (result == 0) break ; - psf_fwrite (odata->opage.header, 1, odata->opage.header_len, psf) ; - psf_fwrite (odata->opage.body, 1, odata->opage.body_len, psf) ; - - /* 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 (&odata->opage)) odata->eos = 1 ; - } - } - } - } - - /* ogg_page and ogg_packet structs always point to storage in - libvorbis. They are never freed or manipulated directly */ - - vorbis_block_clear (&vdata->vblock) ; - vorbis_dsp_clear (&vdata->vdsp) ; - vorbis_comment_clear (&vdata->vcomment) ; - vorbis_info_clear (&vdata->vinfo) ; - - return 0 ; -} /* vorbis_close */ - -int -ogg_vorbis_open (SF_PRIVATE *psf) -{ OGG_PRIVATE* odata = psf->container_data ; - VORBIS_PRIVATE* vdata = calloc (1, sizeof (VORBIS_PRIVATE)) ; - int error = 0 ; - - if (odata == NULL) - { psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ; - return SFE_INTERNAL ; - } ; - - psf->codec_data = vdata ; - - if (psf->file.mode == SFM_RDWR) - return SFE_BAD_MODE_RW ; - - psf_log_printf (psf, "Vorbis library version : %s\n", vorbis_version_string ()) ; - - if (psf->file.mode == SFM_READ) - { /* Call this here so it only gets called once, so no memory is leaked. */ - ogg_sync_init (&odata->osync) ; - - if ((error = vorbis_read_header (psf, 1))) - return error ; - - psf->read_short = vorbis_read_s ; - psf->read_int = vorbis_read_i ; - psf->read_float = vorbis_read_f ; - psf->read_double = vorbis_read_d ; - psf->sf.frames = vorbis_length (psf) ; - } ; - - psf->codec_close = vorbis_close ; - if (psf->file.mode == SFM_WRITE) - { - /* Set the default vorbis quality here. */ - vdata->quality = 0.4 ; - - psf->write_header = vorbis_write_header ; - psf->write_short = vorbis_write_s ; - psf->write_int = vorbis_write_i ; - psf->write_float = vorbis_write_f ; - psf->write_double = vorbis_write_d ; - - psf->sf.frames = SF_COUNT_MAX ; /* Unknown really */ - psf->str_flags = SF_STR_ALLOW_START ; - } ; - - psf->bytewidth = 1 ; - psf->blockwidth = psf->bytewidth * psf->sf.channels ; - - psf->seek = vorbis_seek ; - psf->command = vorbis_command ; - - /* FIXME, FIXME, FIXME : Hack these here for now and correct later. */ - psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; - psf->sf.sections = 1 ; - - psf->datalength = 1 ; - psf->dataoffset = 0 ; - /* End FIXME. */ - - return error ; -} /* ogg_vorbis_open */ - -static int -vorbis_command (SF_PRIVATE *psf, int command, void * data, int datasize) -{ VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - - switch (command) - { case SFC_SET_VBR_ENCODING_QUALITY : - if (data == NULL || datasize != sizeof (double)) - return SF_FALSE ; - - if (psf->have_written) - return SF_FALSE ; - - vdata->quality = *((double *) data) ; - - /* Clip range. */ - vdata->quality = SF_MAX (0.0, SF_MIN (1.0, vdata->quality)) ; - - psf_log_printf (psf, "%s : Setting SFC_SET_VBR_ENCODING_QUALITY to %f.\n", __func__, vdata->quality) ; - return SF_TRUE ; - - default : - return SF_FALSE ; - } ; - - return SF_FALSE ; -} /* vorbis_command */ - -static int -vorbis_rnull (int samples, void *UNUSED (vptr), int UNUSED (off) , int channels, float **UNUSED (pcm)) -{ - return samples * channels ; -} /* vorbis_rnull */ - -static int -vorbis_rshort (int samples, void *vptr, int off, int channels, float **pcm) -{ - short *ptr = (short*) vptr + off ; - int i = 0, j, n ; - for (j = 0 ; j < samples ; j++) - for (n = 0 ; n < channels ; n++) - ptr [i++] = lrintf (pcm [n][j] * 32767.0f) ; - return i ; -} /* vorbis_rshort */ - -static int -vorbis_rint (int samples, void *vptr, int off, int channels, float **pcm) -{ - int *ptr = (int*) vptr + off ; - int i = 0, j, n ; - - for (j = 0 ; j < samples ; j++) - for (n = 0 ; n < channels ; n++) - ptr [i++] = lrintf (pcm [n][j] * 2147483647.0f) ; - return i ; -} /* vorbis_rint */ - -static int -vorbis_rfloat (int samples, void *vptr, int off, int channels, float **pcm) -{ - float *ptr = (float*) vptr + off ; - int i = 0, j, n ; - for (j = 0 ; j < samples ; j++) - for (n = 0 ; n < channels ; n++) - ptr [i++] = pcm [n][j] ; - return i ; -} /* vorbis_rfloat */ - -static int -vorbis_rdouble (int samples, void *vptr, int off, int channels, float **pcm) -{ - double *ptr = (double*) vptr + off ; - int i = 0, j, n ; - for (j = 0 ; j < samples ; j++) - for (n = 0 ; n < channels ; n++) - ptr [i++] = pcm [n][j] ; - return i ; -} /* vorbis_rdouble */ - - -static sf_count_t -vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) -{ - VORBIS_PRIVATE *vdata = psf->codec_data ; - OGG_PRIVATE *odata = psf->container_data ; - int len, samples, i = 0 ; - float **pcm ; - - len = lens / psf->sf.channels ; - - while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0) - { if (samples > len) samples = len ; - i += transfn (samples, ptr, i, psf->sf.channels, pcm) ; - len -= samples ; - /* tell libvorbis how many samples we actually consumed */ - vorbis_synthesis_read (&vdata->vdsp, samples) ; - vdata->loc += samples ; - if (len == 0) - return i ; /* Is this necessary */ - } - goto start0 ; /* Jump into the nasty nest */ - while (len > 0 && !odata->eos) - { - while (len > 0 && !odata->eos) - { int result = ogg_sync_pageout (&odata->osync, &odata->opage) ; - if (result == 0) break ; /* need more data */ - if (result < 0) - { /* missing or corrupt data at this page position */ - psf_log_printf (psf, "Corrupt or missing data in bitstream ; continuing...\n") ; - } - else - { /* can safely ignore errors at this point */ - ogg_stream_pagein (&odata->ostream, &odata->opage) ; - start0: - while (1) - { result = ogg_stream_packetout (&odata->ostream, &odata->opacket) ; - if (result == 0) - break ; /* need more data */ - if (result < 0) - { /* missing or corrupt data at this page position */ - /* no reason to complain ; already complained above */ - } - else - { /* we have a packet. Decode it */ - if (vorbis_synthesis (&vdata->vblock, &odata->opacket) == 0) /* test for success! */ - vorbis_synthesis_blockin (&vdata->vdsp, &vdata->vblock) ; - /* - **pcm is a multichannel float vector. In stereo, for - example, pcm [0] is left, and pcm [1] is right. samples is - the size of each channel. Convert the float values - (-1.<=range<=1.) to whatever PCM format and write it out */ - - while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0) - { if (samples>len) samples = len ; - i += transfn (samples, ptr, i, psf->sf.channels, pcm) ; - len -= samples ; - /* tell libvorbis how many samples we actually consumed */ - vorbis_synthesis_read (&vdata->vdsp, samples) ; - vdata->loc += samples ; - if (len == 0) - return i ; /* Is this necessary */ - } ; - } - } - if (ogg_page_eos (&odata->opage)) odata->eos = 1 ; - } - } - if (!odata->eos) - { char *buffer ; - int bytes ; - buffer = ogg_sync_buffer (&odata->osync, 4096) ; - bytes = psf_fread (buffer, 1, 4096, psf) ; - ogg_sync_wrote (&odata->osync, bytes) ; - if (bytes == 0) odata->eos = 1 ; - } - } - return i ; -} /* vorbis_read_sample */ - -static sf_count_t -vorbis_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t lens) -{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rshort) ; -} /* vorbis_read_s */ - -static sf_count_t -vorbis_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t lens) -{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rint) ; -} /* vorbis_read_i */ - -static sf_count_t -vorbis_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t lens) -{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rfloat) ; -} /* vorbis_read_f */ - -static sf_count_t -vorbis_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t lens) -{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rdouble) ; -} /* vorbis_read_d */ - -/*============================================================================== -*/ - -static void -vorbis_write_samples (SF_PRIVATE *psf, OGG_PRIVATE *odata, VORBIS_PRIVATE *vdata, int in_frames) -{ - vorbis_analysis_wrote (&vdata->vdsp, in_frames) ; - - /* - ** 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 (&vdata->vdsp, &vdata->vblock) == 1) - { - /* analysis, assume we want to use bitrate management */ - vorbis_analysis (&vdata->vblock, NULL) ; - vorbis_bitrate_addblock (&vdata->vblock) ; - - while (vorbis_bitrate_flushpacket (&vdata->vdsp, &odata->opacket)) - { - /* weld the packet into the bitstream */ - ogg_stream_packetin (&odata->ostream, &odata->opacket) ; - - /* write out pages (if any) */ - while (!odata->eos) - { int result = ogg_stream_pageout (&odata->ostream, &odata->opage) ; - if (result == 0) - break ; - psf_fwrite (odata->opage.header, 1, odata->opage.header_len, psf) ; - psf_fwrite (odata->opage.body, 1, odata->opage.body_len, psf) ; - - /* 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 (&odata->opage)) - odata->eos = 1 ; - } ; - } ; - } ; - - vdata->loc += in_frames ; -} /* vorbis_write_data */ - - -static sf_count_t -vorbis_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t lens) -{ - int i, m, j = 0 ; - OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; - VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - int in_frames = lens / psf->sf.channels ; - float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; - for (i = 0 ; i < in_frames ; i++) - for (m = 0 ; m < psf->sf.channels ; m++) - buffer [m][i] = (float) (ptr [j++]) / 32767.0f ; - - vorbis_write_samples (psf, odata, vdata, in_frames) ; - - return lens ; -} /* vorbis_write_s */ - -static sf_count_t -vorbis_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t lens) -{ int i, m, j = 0 ; - OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; - VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - int in_frames = lens / psf->sf.channels ; - float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; - for (i = 0 ; i < in_frames ; i++) - for (m = 0 ; m < psf->sf.channels ; m++) - buffer [m][i] = (float) (ptr [j++]) / 2147483647.0f ; - - vorbis_write_samples (psf, odata, vdata, in_frames) ; - - return lens ; -} /* vorbis_write_i */ - -static sf_count_t -vorbis_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t lens) -{ int i, m, j = 0 ; - OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; - VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - int in_frames = lens / psf->sf.channels ; - float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; - for (i = 0 ; i < in_frames ; i++) - for (m = 0 ; m < psf->sf.channels ; m++) - buffer [m][i] = ptr [j++] ; - - vorbis_write_samples (psf, odata, vdata, in_frames) ; - - return lens ; -} /* vorbis_write_f */ - -static sf_count_t -vorbis_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t lens) -{ int i, m, j = 0 ; - OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; - VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - int in_frames = lens / psf->sf.channels ; - float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; - for (i = 0 ; i < in_frames ; i++) - for (m = 0 ; m < psf->sf.channels ; m++) - buffer [m][i] = (float) ptr [j++] ; - - vorbis_write_samples (psf, odata, vdata, in_frames) ; - - return lens ; -} /* vorbis_write_d */ - -static sf_count_t -vorbis_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset) -{ - OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; - VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; - - if (odata == NULL || vdata == NULL) - return 0 ; - - if (offset < 0) - { psf->error = SFE_BAD_SEEK ; - return ((sf_count_t) -1) ; - } ; - - if (psf->file.mode == SFM_READ) - { sf_count_t target = offset - vdata->loc ; - - if (target < 0) - { /* 12 to allow for OggS bit */ - psf_fseek (psf, 12, SEEK_SET) ; - vorbis_read_header (psf, 0) ; /* Reset state */ - target = offset ; - } ; - - while (target > 0) - { sf_count_t m = target > 4096 ? 4096 : target ; - - /* - ** Need to multiply by channels here because the seek is done in - ** terms of frames and the read function is done in terms of - ** samples. - */ - vorbis_read_sample (psf, (void *) NULL, m * psf->sf.channels, vorbis_rnull) ; - - target -= m ; - } ; - - return vdata->loc ; - } ; - - return 0 ; -} /* vorbis_seek */ - -/*============================================================================== -** Most of the following code was snipped from Mike Smith's ogginfo utility -** which is part of vorbis-tools. -** Vorbis tools is released under the GPL but Mike has kindly allowed the -** following to be relicensed as LGPL for libsndfile. -*/ - -typedef struct -{ - int isillegal ; - int shownillegal ; - int isnew ; - int end ; - - uint32_t serial ; /* must be 32 bit unsigned */ - ogg_stream_state ostream ; - - vorbis_info vinfo ; - vorbis_comment vcomment ; - sf_count_t lastgranulepos ; - int doneheaders ; -} stream_processor ; - -typedef struct -{ - stream_processor *streams ; - int allocated ; - int used ; - int in_headers ; -} stream_set ; - -static stream_set * -create_stream_set (void) -{ stream_set *set = calloc (1, sizeof (stream_set)) ; - - set->streams = calloc (5, sizeof (stream_processor)) ; - set->allocated = 5 ; - set->used = 0 ; - - return set ; -} /* create_stream_set */ - -static void -vorbis_end (stream_processor *stream, sf_count_t * len) -{ *len += stream->lastgranulepos ; - vorbis_comment_clear (&stream->vcomment) ; - vorbis_info_clear (&stream->vinfo) ; -} /* vorbis_end */ - -static void -free_stream_set (stream_set *set, sf_count_t * len) -{ int i ; - - for (i = 0 ; i < set->used ; i++) - { if (!set->streams [i].end) - vorbis_end (&set->streams [i], len) ; - ogg_stream_clear (&set->streams [i].ostream) ; - } ; - - free (set->streams) ; - free (set) ; -} /* free_stream_set */ - -static int -streams_open (stream_set *set) -{ int i, res = 0 ; - - for (i = 0 ; i < set->used ; i++) - if (!set->streams [i].end) - res ++ ; - return res ; -} /* streams_open */ - -static stream_processor * -find_stream_processor (stream_set *set, ogg_page *page) -{ uint32_t serial = ogg_page_serialno (page) ; - int i, invalid = 0 ; - - stream_processor *stream ; - - for (i = 0 ; i < set->used ; i++) - { - if (serial == set->streams [i].serial) - { /* We have a match! */ - stream = & (set->streams [i]) ; - - set->in_headers = 0 ; - /* if we have detected EOS, then this can't occur here. */ - if (stream->end) - { stream->isillegal = 1 ; - return stream ; - } - - stream->isnew = 0 ; - stream->end = ogg_page_eos (page) ; - stream->serial = serial ; - return stream ; - } ; - } ; - - /* If there are streams open, and we've reached the end of the - ** headers, then we can't be starting a new stream. - ** XXX: might this sometimes catch ok streams if EOS flag is missing, - ** but the stream is otherwise ok? - */ - if (streams_open (set) && !set->in_headers) - invalid = 1 ; - - set->in_headers = 1 ; - - if (set->allocated < set->used) - stream = &set->streams [set->used] ; - else - { set->allocated += 5 ; - set->streams = realloc (set->streams, sizeof (stream_processor) * set->allocated) ; - stream = &set->streams [set->used] ; - } ; - - set->used++ ; - - stream->isnew = 1 ; - stream->isillegal = invalid ; - - { - int res ; - ogg_packet packet ; - - /* We end up processing the header page twice, but that's ok. */ - ogg_stream_init (&stream->ostream, serial) ; - ogg_stream_pagein (&stream->ostream, page) ; - res = ogg_stream_packetout (&stream->ostream, &packet) ; - if (res <= 0) - return NULL ; - else if (packet.bytes >= 7 && memcmp (packet.packet, "\x01vorbis", 7) == 0) - { - stream->lastgranulepos = 0 ; - vorbis_comment_init (&stream->vcomment) ; - vorbis_info_init (&stream->vinfo) ; - } ; - - res = ogg_stream_packetout (&stream->ostream, &packet) ; - - /* re-init, ready for processing */ - ogg_stream_clear (&stream->ostream) ; - ogg_stream_init (&stream->ostream, serial) ; - } - - stream->end = ogg_page_eos (page) ; - stream->serial = serial ; - - return stream ; -} /* find_stream_processor */ - -static int -vorbis_length_get_next_page (SF_PRIVATE *psf, ogg_sync_state * osync, ogg_page *page) -{ static const int CHUNK_SIZE = 4500 ; - - while (ogg_sync_pageout (osync, page) <= 0) - { char * buffer = ogg_sync_buffer (osync, CHUNK_SIZE) ; - int bytes = psf_fread (buffer, 1, 4096, psf) ; - - if (bytes <= 0) - { ogg_sync_wrote (osync, 0) ; - return 0 ; - } ; - - ogg_sync_wrote (osync, bytes) ; - } ; - - return 1 ; -} /* vorbis_length_get_next_page */ - -static sf_count_t -vorbis_length_aux (SF_PRIVATE * psf) -{ - ogg_sync_state osync ; - ogg_page page ; - sf_count_t len = 0 ; - stream_set *processors ; - - processors = create_stream_set () ; - if (processors == NULL) - return 0 ; // out of memory? - - ogg_sync_init (&osync) ; - - while (vorbis_length_get_next_page (psf, &osync, &page)) - { - stream_processor *p = find_stream_processor (processors, &page) ; - - if (!p) - { len = 0 ; - break ; - } ; - - if (p->isillegal && !p->shownillegal) - { - p->shownillegal = 1 ; - /* If it's a new stream, we want to continue processing this page - ** anyway to suppress additional spurious errors - */ - if (!p->isnew) continue ; - } ; - - if (!p->isillegal) - { ogg_packet packet ; - int header = 0 ; - - ogg_stream_pagein (&p->ostream, &page) ; - if (p->doneheaders < 3) - header = 1 ; - - while (ogg_stream_packetout (&p->ostream, &packet) > 0) - { - if (p->doneheaders < 3) - { if (vorbis_synthesis_headerin (&p->vinfo, &p->vcomment, &packet) < 0) - continue ; - p->doneheaders ++ ; - } ; - } ; - if (!header) - { sf_count_t gp = ogg_page_granulepos (&page) ; - if (gp > 0) p->lastgranulepos = gp ; - } ; - if (p->end) - { vorbis_end (p, &len) ; - p->isillegal = 1 ; - } ; - } ; - } ; - - ogg_sync_clear (&osync) ; - free_stream_set (processors, &len) ; - - return len ; -} /* vorbis_length_aux */ - -static sf_count_t -vorbis_length (SF_PRIVATE *psf) -{ sf_count_t length ; - int error ; - - if (psf->sf.seekable == 0) - return SF_COUNT_MAX ; - - psf_fseek (psf, 0, SEEK_SET) ; - length = vorbis_length_aux (psf) ; - - psf_fseek (psf, 12, SEEK_SET) ; - if ((error = vorbis_read_header (psf, 0)) != 0) - psf->error = error ; - - return length ; -} /* vorbis_length */ - -#else /* HAVE_EXTERNAL_LIBS */ - -int -ogg_vorbis_open (SF_PRIVATE *psf) -{ - psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ; - return SFE_UNIMPLEMENTED ; -} /* ogg_vorbis_open */ - -#endif