2 ** Copyright (C) 2002-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2002-2005 Michael Smith <msmith@xiph.org>
4 ** Copyright (C) 2007 John ffitch
6 ** This program is free software ; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation ; either version 2.1 of the License, or
9 ** (at your option) any later version.
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY ; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU Lesser General Public License for more details.
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program ; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 ** Much of this code is based on the examples in libvorbis from the
23 ** XIPHOPHORUS Company http://www.xiph.org/ which has a BSD-style Licence
24 ** Copyright (c) 2002, Xiph.org Foundation
26 ** Redistribution and use in source and binary forms, with or without
27 ** modification, are permitted provided that the following conditions
30 ** - Redistributions of source code must retain the above copyright
31 ** notice, this list of conditions and the following disclaimer.
33 ** - Redistributions in binary form must reproduce the above copyright
34 ** notice, this list of conditions and the following disclaimer in the
35 ** documentation and/or other materials provided with the distribution.
37 ** - Neither the name of the Xiph.org Foundation nor the names of its
38 ** contributors may be used to endorse or promote products derived from
39 ** this software without specific prior written permission.
41 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
42 ** ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
43 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
44 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
45 ** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE,
48 ** DATA, OR PROFITS ; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
51 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66 #include "sf_unistd.h"
73 #if HAVE_EXTERNAL_XIPH_LIBS
77 #include <vorbis/codec.h>
80 #include <dlfcn.h> /* for dlopen */
82 #include <vorbis/vorbisenc.h>
87 typedef int convert_func (SF_PRIVATE *psf, int, void *, int, int, float **) ;
89 static int vorbis_read_header (SF_PRIVATE *psf) ;
90 static int vorbis_write_header (SF_PRIVATE *psf, int calc_length) ;
91 static int vorbis_close (SF_PRIVATE *psf) ;
92 static int vorbis_command (SF_PRIVATE *psf, int command, void *data, int datasize) ;
93 static int vorbis_byterate (SF_PRIVATE *psf) ;
94 static sf_count_t vorbis_calculate_page_duration (SF_PRIVATE *psf) ;
95 static sf_count_t vorbis_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
96 static sf_count_t vorbis_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
97 static sf_count_t vorbis_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
98 static sf_count_t vorbis_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
99 static sf_count_t vorbis_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
100 static sf_count_t vorbis_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
101 static sf_count_t vorbis_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
102 static sf_count_t vorbis_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
103 static sf_count_t vorbis_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
104 static sf_count_t vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) ;
105 static int vorbis_rnull (SF_PRIVATE *psf, int samples, void *vptr, int off , int channels, float **pcm) ;
113 /* See https://xiph.org/vorbis/doc/v-comment.html */
114 static STR_PAIRS vorbis_metatypes [] =
115 { { SF_STR_TITLE, "Title" },
116 { SF_STR_COPYRIGHT, "Copyright" },
117 { SF_STR_SOFTWARE, "Software" },
118 { SF_STR_ARTIST, "Artist" },
119 { SF_STR_COMMENT, "Comment" },
120 { SF_STR_DATE, "Date" },
121 { SF_STR_ALBUM, "Album" },
122 { SF_STR_LICENSE, "License" },
123 { SF_STR_TRACKNUMBER, "Tracknumber" },
124 { SF_STR_GENRE, "Genre" },
128 { /* Count current location */
130 /* Struct that stores all the static vorbis bitstream settings */
132 /* Struct that stores all the bitstream user comments */
133 vorbis_comment vcomment ;
134 /* Ventral working state for the packet->PCM decoder */
135 vorbis_dsp_state vdsp ;
136 /* Local working space for packet->PCM decode */
137 vorbis_block vblock ;
139 /* Encoding quality in range [0.0, 1.0]. */
142 /* Current granule position. */
143 uint64_t pcm_current ;
144 /* Offset of the first samples' granule position. */
146 /* Last valid samples' granule position. */
148 /* File offset of the start of the last page. */
149 sf_count_t last_page ;
151 /* func ptr for encoder */
157 vorbis_read_header (SF_PRIVATE *psf)
158 { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
159 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
160 sf_count_t duration ;
161 int printed_metadata_msg = 0 ;
165 ** The first page of the Ogg stream we are told to try and open as Vorbis
166 ** has already been loaded into odata->ostream by ogg_open().
168 ** Extract the initial header from the first page and verify that the
169 ** Ogg bitstream is in fact Vorbis data.
172 vorbis_info_init (&vdata->vinfo) ;
173 vorbis_comment_init (&vdata->vcomment) ;
175 if (!odata->opacket.b_o_s)
176 { psf_log_printf (psf, "Vorbis: First packet does not have a beginning-of-stream bit.\n") ;
177 return SFE_MALFORMED_FILE ;
180 if (ogg_stream_packetpeek (&odata->ostream, NULL))
181 { psf_log_printf (psf, "Vorbis: First page contains extraneous packets!\n") ;
182 return SFE_MALFORMED_FILE ;
185 if (vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) < 0)
186 { /* Error case ; not a vorbis header. */
187 psf_log_printf (psf, "Found Vorbis in stream header, but vorbis_synthesis_headerin failed.\n") ;
188 return SFE_MALFORMED_FILE ;
192 ** At this point, we're sure we're Vorbis. We've set up the logical (Ogg)
193 ** bitstream decoder. Get the comment and codebook headers and set up the
196 ** The next two packets in order are the comment and codebook headers.
197 ** They're likely large and may span multiple pages. Thus we reead
198 ** and submit data until we get our two pacakets, watching that no
199 ** pages are missing. If a page is missing, error out ; losing a
200 ** header page is the only place where missing data is fatal.
203 i = 0 ; /* Count of number of packets read */
205 { nn = ogg_stream_packetout (&odata->ostream, &odata->opacket) ;
208 { nn = ogg_stream_next_page (psf, odata) ;
210 { psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ;
211 return SFE_MALFORMED_FILE ;
214 { psf_log_printf (psf, "Error reading file while finding Vorbis headers!\n") ;
221 { /* A hole while reading headers. This could be bad. */
222 psf_log_printf (psf, "Corrupt secondary header. Exiting.\n") ;
223 return SFE_MALFORMED_FILE ;
226 vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) ;
230 /* Check for extraneous packets in the last headers page. */
231 while (ogg_stream_packetout (&odata->ostream, &odata->opacket) == 1)
235 psf_log_printf (psf, "Vorbis: stream has extraneous header packets.\n") ;
237 psf_log_printf (psf, "Bitstream is %d channel, %D Hz\n", vdata->vinfo.channels, vdata->vinfo.rate) ;
238 psf_log_printf (psf, "Encoded by : %s\n", vdata->vcomment.vendor) ;
240 /* Save the offset of the first payload page */
241 psf->dataoffset = ogg_sync_ftell (psf) ;
244 ** Caculate the granule position offset. The first page with a payload
245 ** packet shouldn't end in a continued packet. The difference between the
246 ** page's granule position and the sum of frames on the page tells us the
247 ** granule position offset.
248 ** See https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-132000A.2
250 ogg_stream_unpack_page (psf, odata) ;
251 vdata->pcm_start = odata->pkt [odata->pkt_len - 1].granulepos ;
252 duration = vorbis_calculate_page_duration (psf) ;
254 if (duration < (sf_count_t) vdata->pcm_start)
255 vdata->pcm_start -= duration ;
257 vdata->pcm_start = 0 ;
260 ** Find the end of the stream, save it. Only works if the file is seekable.
262 vdata->loc = vdata->pcm_start ;
263 vdata->pcm_end = (uint64_t) -1 ;
264 psf->datalength = psf->filelength ;
266 { sf_count_t last_page ;
267 sf_count_t saved_offset ;
269 saved_offset = ogg_sync_ftell (psf) ;
270 last_page = ogg_sync_last_page_before (psf, odata, &vdata->pcm_end, psf->filelength, odata->ostream.serialno) ;
272 { if (!ogg_page_eos (&odata->opage))
273 psf_log_printf (psf, "Ogg: Last page lacks an end-of-stream bit.\n") ;
274 psf->datalength = last_page + odata->opage.header_len + odata->opage.body_len - psf->dataoffset ;
275 if (psf->datalength + psf->dataoffset < psf->filelength)
276 psf_log_printf (psf, "Ogg: Junk after the last page.\n") ;
277 vdata->last_page = last_page ;
280 ogg_sync_fseek (psf, saved_offset, SEEK_SET) ;
283 psf_log_printf (psf, "PCM offset : %d\n", vdata->pcm_start) ;
284 if (vdata->pcm_end != (uint64_t) -1)
285 psf_log_printf (psf, "PCM end : %d\n", vdata->pcm_end) ;
287 psf_log_printf (psf, "PCM end : unknown\n") ;
289 /* Throw the comments plus a few lines about the bitstream we're decoding. */
290 for (k = 0 ; k < ARRAY_LEN (vorbis_metatypes) ; k++)
293 dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [k].name, 0) ;
297 if (printed_metadata_msg == 0)
298 { psf_log_printf (psf, "Metadata :\n") ;
299 printed_metadata_msg = 1 ;
302 psf_store_string (psf, vorbis_metatypes [k].id, dd) ;
303 psf_log_printf (psf, " %-10s : %s\n", vorbis_metatypes [k].name, dd) ;
305 psf_log_printf (psf, "End\n") ;
307 psf->sf.samplerate = vdata->vinfo.rate ;
308 psf->sf.channels = vdata->vinfo.channels ;
309 psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ;
310 psf->sf.frames = (vdata->pcm_end != (uint64_t) -1) ? vdata->pcm_end - vdata->pcm_start : SF_COUNT_MAX ;
312 /* OK, got and parsed all three headers. Initialize the Vorbis
313 ** packet->PCM decoder.
314 ** Central decode state. */
315 vorbis_synthesis_init (&vdata->vdsp, &vdata->vinfo) ;
317 /* Local state for most of the decode so multiple block decodes can
318 ** proceed in parallel. We could init multiple vorbis_block structures
320 vorbis_block_init (&vdata->vdsp, &vdata->vblock) ;
323 } /* vorbis_read_header */
327 #define VORBIS_ENC_SO_NAME "/usr/lib/libvorbisenc.so.2" /* FIXME : Any good way to avoid hardcoding? */
328 #define VORBIS_ENC_INIT_VBR "vorbis_encode_init_vbr"
331 _vorbis_encode_init(SF_PRIVATE *psf)
333 int (*fn) (vorbis_info *, long, long, float);
335 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
338 dl = dlopen(VORBIS_ENC_SO_NAME, RTLD_GLOBAL | RTLD_NOW);
340 psf_log_printf (psf, "failed to dlopen [%s], error [%s]\n", VORBIS_ENC_SO_NAME, dlerror());
348 fn = dlsym(dl, VORBIS_ENC_INIT_VBR);
350 psf_log_printf (psf, "failed to dlsym [%s], error [%s]\n", VORBIS_ENC_INIT_VBR, dlerror());
356 return fn(&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, vdata->quality);
358 #endif /* __TIZEN__ */
361 vorbis_write_header (SF_PRIVATE *psf, int UNUSED (calc_length))
363 OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
364 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
367 vorbis_info_init (&vdata->vinfo) ;
369 /* The style of encoding should be selectable here, VBR quality mode. */
371 ret = _vorbis_encode_init(psf);
373 ret = vorbis_encode_init_vbr (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, vdata->quality) ;
377 ret = vorbis_encode_init (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, -1, 128000, -1) ; /* average bitrate mode */
378 ret = ( vorbis_encode_setup_managed (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, -1, 128000, -1)
379 || vorbis_encode_ctl (&vdata->vinfo, OV_ECTL_RATEMANAGE_AVG, NULL)
380 || vorbis_encode_setup_init (&vdata->vinfo)
384 return SFE_BAD_OPEN_FORMAT ;
389 vorbis_comment_init (&vdata->vcomment) ;
391 vorbis_comment_add_tag (&vdata->vcomment, "ENCODER", "libsndfile") ;
392 for (k = 0 ; k < SF_MAX_STRINGS ; k++)
393 { const char * name ;
395 if (psf->strings.data [k].type == 0)
398 switch (psf->strings.data [k].type)
399 { case SF_STR_TITLE : name = "TITLE" ; break ;
400 case SF_STR_COPYRIGHT : name = "COPYRIGHT" ; break ;
401 case SF_STR_SOFTWARE : name = "SOFTWARE" ; break ;
402 case SF_STR_ARTIST : name = "ARTIST" ; break ;
403 case SF_STR_COMMENT : name = "COMMENT" ; break ;
404 case SF_STR_DATE : name = "DATE" ; break ;
405 case SF_STR_ALBUM : name = "ALBUM" ; break ;
406 case SF_STR_LICENSE : name = "LICENSE" ; break ;
407 case SF_STR_TRACKNUMBER : name = "Tracknumber" ; break ;
408 case SF_STR_GENRE : name = "Genre" ; break ;
413 vorbis_comment_add_tag (&vdata->vcomment, name, psf->strings.storage + psf->strings.data [k].offset) ;
416 /* set up the analysis state and auxiliary encoding storage */
417 vorbis_analysis_init (&vdata->vdsp, &vdata->vinfo) ;
418 vorbis_block_init (&vdata->vdsp, &vdata->vblock) ;
421 ** Set up our packet->stream encoder.
422 ** Pick a random serial number ; that way we can more likely build
423 ** chained streams just by concatenation.
426 ogg_stream_init (&odata->ostream, psf_rand_int32 ()) ;
428 /* Vorbis streams begin with three headers ; the initial header (with
429 most of the codec setup parameters) which is mandated by the Ogg
430 bitstream spec. The second header holds any comment fields. The
431 third header holds the bitstream codebook. We merely need to
432 make the headers, then pass them to libvorbis one at a time ;
433 libvorbis handles the additional Ogg bitstream constraints */
435 { ogg_packet header ;
436 ogg_packet header_comm ;
437 ogg_packet header_code ;
440 vorbis_analysis_headerout (&vdata->vdsp, &vdata->vcomment, &header, &header_comm, &header_code) ;
441 ogg_stream_packetin (&odata->ostream, &header) ; /* automatically placed in its own page */
442 ogg_stream_packetin (&odata->ostream, &header_comm) ;
443 ogg_stream_packetin (&odata->ostream, &header_code) ;
445 /* This ensures the actual
446 * audio data will start on a new page, as per spec
448 while ((result = ogg_stream_flush (&odata->ostream, &odata->opage)) != 0)
449 { ogg_write_page (psf, &odata->opage) ;
454 } /* vorbis_write_header */
457 vorbis_close (SF_PRIVATE *psf)
458 { OGG_PRIVATE* odata = psf->container_data ;
459 VORBIS_PRIVATE *vdata = psf->codec_data ;
461 if (odata == NULL || vdata == NULL)
464 /* Clean up this logical bitstream ; before exit we shuld see if we're
465 ** followed by another [chained]. */
467 if (psf->file.mode == SFM_WRITE)
469 if (psf->write_current <= 0)
470 vorbis_write_header (psf, 0) ;
472 vorbis_analysis_wrote (&vdata->vdsp, 0) ;
473 while (vorbis_analysis_blockout (&vdata->vdsp, &vdata->vblock) == 1)
476 /* analysis, assume we want to use bitrate management */
477 vorbis_analysis (&vdata->vblock, NULL) ;
478 vorbis_bitrate_addblock (&vdata->vblock) ;
480 while (vorbis_bitrate_flushpacket (&vdata->vdsp, &odata->opacket))
481 { /* weld the packet into the bitstream */
482 ogg_stream_packetin (&odata->ostream, &odata->opacket) ;
484 /* write out pages (if any) */
486 { int result = ogg_stream_pageout (&odata->ostream, &odata->opage) ;
487 if (result == 0) break ;
488 ogg_write_page (psf, &odata->opage) ;
490 /* this could be set above, but for illustrative purposes, I do
491 it here (to show that vorbis does know where the stream ends) */
493 if (ogg_page_eos (&odata->opage)) odata->eos = 1 ;
499 /* ogg_page and ogg_packet structs always point to storage in
500 libvorbis. They are never freed or manipulated directly */
502 vorbis_block_clear (&vdata->vblock) ;
503 vorbis_dsp_clear (&vdata->vdsp) ;
504 vorbis_comment_clear (&vdata->vcomment) ;
505 vorbis_info_clear (&vdata->vinfo) ;
518 ogg_vorbis_open (SF_PRIVATE *psf)
519 { OGG_PRIVATE* odata = psf->container_data ;
520 VORBIS_PRIVATE* vdata ;
524 { psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ;
525 return SFE_INTERNAL ;
528 vdata = calloc (1, sizeof (VORBIS_PRIVATE)) ;
529 psf->codec_data = vdata ;
531 if (psf->file.mode == SFM_RDWR)
532 return SFE_BAD_MODE_RW ;
534 psf_log_printf (psf, "Vorbis library version : %s\n", vorbis_version_string ()) ;
536 if (psf->file.mode == SFM_READ)
537 { if ((error = vorbis_read_header (psf)))
540 psf->read_short = vorbis_read_s ;
541 psf->read_int = vorbis_read_i ;
542 psf->read_float = vorbis_read_f ;
543 psf->read_double = vorbis_read_d ;
546 psf->codec_close = vorbis_close ;
547 if (psf->file.mode == SFM_WRITE)
549 /* Set the default vorbis quality here. */
550 vdata->quality = 0.4 ;
552 psf->write_header = vorbis_write_header ;
553 psf->write_short = vorbis_write_s ;
554 psf->write_int = vorbis_write_i ;
555 psf->write_float = vorbis_write_f ;
556 psf->write_double = vorbis_write_d ;
559 psf->datalength = 0 ;
560 psf->filelength = 0 ;
561 psf->dataoffset = 0 ;
562 psf->strings.flags = SF_STR_ALLOW_START ;
565 psf->seek = vorbis_seek ;
566 psf->command = vorbis_command ;
567 psf->byterate = vorbis_byterate ;
568 psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ;
569 psf->sf.sections = 1 ;
572 } /* ogg_vorbis_open */
575 vorbis_command (SF_PRIVATE *psf, int command, void * data, int datasize)
576 { VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
579 { case SFC_SET_COMPRESSION_LEVEL :
580 if (data == NULL || datasize != sizeof (double))
583 if (psf->have_written)
586 vdata->quality = 1.0 - *((double *) data) ;
589 vdata->quality = SF_MAX (0.0, SF_MIN (1.0, vdata->quality)) ;
591 psf_log_printf (psf, "%s : Setting SFC_SET_VBR_ENCODING_QUALITY to %f.\n", __func__, vdata->quality) ;
599 } /* vorbis_command */
602 vorbis_rnull (SF_PRIVATE *UNUSED (psf), int samples, void *UNUSED (vptr), int UNUSED (off) , int channels, float **UNUSED (pcm))
604 return samples * channels ;
608 vorbis_rshort (SF_PRIVATE *psf, int samples, void *vptr, int off, int channels, float **pcm)
610 short *ptr = (short*) vptr + off ;
612 if (psf->float_int_mult)
614 float inverse = 1.0 / psf->float_max ;
615 for (j = 0 ; j < samples ; j++)
616 for (n = 0 ; n < channels ; n++)
617 ptr [i++] = psf_lrintf ((pcm [n][j] * inverse) * 32767.0f) ;
621 for (j = 0 ; j < samples ; j++)
622 for (n = 0 ; n < channels ; n++)
623 ptr [i++] = psf_lrintf (pcm [n][j] * 32767.0f) ;
626 } /* vorbis_rshort */
629 vorbis_rint (SF_PRIVATE *psf, int samples, void *vptr, int off, int channels, float **pcm)
631 int *ptr = (int*) vptr + off ;
634 if (psf->float_int_mult)
636 float inverse = 1.0 / psf->float_max ;
637 for (j = 0 ; j < samples ; j++)
638 for (n = 0 ; n < channels ; n++)
639 ptr [i++] = psf_lrintf ((pcm [n][j] * inverse) * 2147483647.0f) ;
643 for (j = 0 ; j < samples ; j++)
644 for (n = 0 ; n < channels ; n++)
645 ptr [i++] = psf_lrintf (pcm [n][j] * 2147483647.0f) ;
651 vorbis_rfloat (SF_PRIVATE *UNUSED (psf), int samples, void *vptr, int off, int channels, float **pcm)
653 float *ptr = (float*) vptr + off ;
655 for (j = 0 ; j < samples ; j++)
656 for (n = 0 ; n < channels ; n++)
657 ptr [i++] = pcm [n][j] ;
659 } /* vorbis_rfloat */
662 vorbis_rdouble (SF_PRIVATE *UNUSED (psf), int samples, void *vptr, int off, int channels, float **pcm)
664 double *ptr = (double*) vptr + off ;
666 for (j = 0 ; j < samples ; j++)
667 for (n = 0 ; n < channels ; n++)
668 ptr [i++] = pcm [n][j] ;
670 } /* vorbis_rdouble */
674 vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn)
675 { VORBIS_PRIVATE *vdata = psf->codec_data ;
676 OGG_PRIVATE *odata = psf->container_data ;
677 int len, samples, i = 0 , nn ;
680 len = lens / psf->sf.channels ;
684 ** pcm is a multichannel float vector. In stereo, for
685 ** example, pcm [0] is left, and pcm [1] is right. samples is
686 ** the size of each channel. Convert the float values
687 ** (-1.<=range<=1.) to whatever PCM format and write it out.
689 while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0)
690 { if (samples > len) samples = len ;
691 i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ;
693 /* tell libvorbis how many samples we actually consumed */
694 vorbis_synthesis_read (&vdata->vdsp, samples) ;
695 vdata->loc += samples ;
697 return i ; /* Is this necessary */
700 /* Out of samples, load the next packet. */
701 if (odata->pkt_indx == odata->pkt_len)
702 { /* Page out of packets, load and unpack the next page. */
703 nn = ogg_stream_unpack_page (psf, odata) ;
707 { /* Ran over a hole. loc is now out of date, need to recalculate. */
708 vdata->loc = odata->pkt [odata->pkt_len - 1].granulepos ;
709 vdata->loc -= vorbis_calculate_page_duration (psf) ;
713 /* Decode the packet */
714 if (vorbis_synthesis (&vdata->vblock, &(odata->pkt [odata->pkt_indx])) == 0) /* test for success! */
715 vorbis_synthesis_blockin (&vdata->vdsp, &vdata->vblock) ;
720 } /* vorbis_read_sample */
723 vorbis_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t lens)
724 { return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rshort) ;
725 } /* vorbis_read_s */
728 vorbis_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t lens)
729 { return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rint) ;
730 } /* vorbis_read_i */
733 vorbis_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t lens)
734 { return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rfloat) ;
735 } /* vorbis_read_f */
738 vorbis_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t lens)
739 { return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rdouble) ;
740 } /* vorbis_read_d */
742 /*==============================================================================
746 vorbis_write_samples (SF_PRIVATE *psf, OGG_PRIVATE *odata, VORBIS_PRIVATE *vdata, int in_frames)
748 vorbis_analysis_wrote (&vdata->vdsp, in_frames) ;
751 ** Vorbis does some data preanalysis, then divvies up blocks for
752 ** more involved (potentially parallel) processing. Get a single
753 ** block for encoding now.
755 while (vorbis_analysis_blockout (&vdata->vdsp, &vdata->vblock) == 1)
757 /* analysis, assume we want to use bitrate management */
758 vorbis_analysis (&vdata->vblock, NULL) ;
759 vorbis_bitrate_addblock (&vdata->vblock) ;
761 while (vorbis_bitrate_flushpacket (&vdata->vdsp, &odata->opacket))
763 /* weld the packet into the bitstream */
764 ogg_stream_packetin (&odata->ostream, &odata->opacket) ;
766 /* write out pages (if any) */
768 { int result = ogg_stream_pageout (&odata->ostream, &odata->opage) ;
771 ogg_write_page (psf, &odata->opage) ;
773 /* This could be set above, but for illustrative purposes, I do
774 ** it here (to show that vorbis does know where the stream ends) */
775 if (ogg_page_eos (&odata->opage))
781 vdata->loc += in_frames ;
782 } /* vorbis_write_data */
786 vorbis_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t lens)
789 OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
790 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
791 int in_frames = lens / psf->sf.channels ;
792 float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ;
793 for (i = 0 ; i < in_frames ; i++)
794 for (m = 0 ; m < psf->sf.channels ; m++)
795 buffer [m][i] = (float) (ptr [j++]) / 32767.0f ;
797 vorbis_write_samples (psf, odata, vdata, in_frames) ;
800 } /* vorbis_write_s */
803 vorbis_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t lens)
805 OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
806 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
807 int in_frames = lens / psf->sf.channels ;
808 float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ;
809 for (i = 0 ; i < in_frames ; i++)
810 for (m = 0 ; m < psf->sf.channels ; m++)
811 buffer [m][i] = (float) (ptr [j++]) / 2147483647.0f ;
813 vorbis_write_samples (psf, odata, vdata, in_frames) ;
816 } /* vorbis_write_i */
819 vorbis_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t lens)
821 OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
822 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
823 int in_frames = lens / psf->sf.channels ;
824 float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ;
825 for (i = 0 ; i < in_frames ; i++)
826 for (m = 0 ; m < psf->sf.channels ; m++)
827 buffer [m][i] = ptr [j++] ;
829 vorbis_write_samples (psf, odata, vdata, in_frames) ;
832 } /* vorbis_write_f */
835 vorbis_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t lens)
837 OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
838 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
839 int in_frames = lens / psf->sf.channels ;
840 float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ;
841 for (i = 0 ; i < in_frames ; i++)
842 for (m = 0 ; m < psf->sf.channels ; m++)
843 buffer [m][i] = (float) ptr [j++] ;
845 vorbis_write_samples (psf, odata, vdata, in_frames) ;
848 } /* vorbis_write_d */
851 vorbis_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset)
852 { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
853 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
857 if (odata == NULL || vdata == NULL)
861 { psf->error = SFE_BAD_SEEK ;
862 return ((sf_count_t) -1) ;
865 if (psf->file.mode == SFM_READ)
866 { target = offset + vdata->pcm_start ;
869 ** If the end of the file is know, and the seek isn't for the near
870 ** future, do a search of the file for a good place to start.
873 if ((vdata->pcm_end != (uint64_t) -1) &&
874 (target < vdata->loc || target - vdata->loc > (2 * psf->sf.samplerate)))
877 best_gp = vdata->pcm_start ;
879 ret = ogg_stream_seek_page_search (psf, odata, target, vdata->pcm_start,
880 vdata->pcm_end, &best_gp, psf->dataoffset, vdata->last_page) ;
882 { ret = ogg_stream_unpack_page (psf, odata) ;
884 { vdata->loc = best_gp ;
885 vorbis_synthesis_restart (&vdata->vdsp) ;
890 if (ret >= 0 && offset + (sf_count_t) vdata->pcm_start >= vdata->loc)
891 target = offset + vdata->pcm_start - vdata->loc ;
893 { /* Search failed (bad data?), reset to the beginning of the stream. */
894 ogg_stream_reset_serialno (&odata->ostream, odata->ostream.serialno) ;
896 odata->pkt_indx = 0 ;
897 ogg_sync_fseek (psf, psf->dataoffset, SEEK_SET) ;
899 vorbis_synthesis_restart (&vdata->vdsp) ;
904 { sf_count_t m = target > 4096 ? 4096 : target ;
907 ** Need to multiply by channels here because the seek is done in
908 ** terms of frames and the read function is done in terms of
911 vorbis_read_sample (psf, (void *) NULL, m * psf->sf.channels, vorbis_rnull) ;
916 return vdata->loc - vdata->pcm_start ;
924 vorbis_byterate (SF_PRIVATE *psf)
926 if (psf->file.mode == SFM_READ)
927 return (psf->datalength * psf->sf.samplerate) / psf->sf.frames ;
930 } /* vorbis_byterate */
933 vorbis_calculate_page_duration (SF_PRIVATE *psf)
934 { OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
935 VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
936 long thisblock, lastblock ;
937 sf_count_t duration ;
942 for (i = 0 ; i < odata->pkt_len ; i++)
943 { thisblock = vorbis_packet_blocksize (&vdata->vinfo, &(odata->pkt [i])) ;
945 { if (lastblock != -1)
946 duration += (lastblock + thisblock) >> 2 ;
947 lastblock = thisblock ;
954 #else /* HAVE_EXTERNAL_XIPH_LIBS */
957 ogg_vorbis_open (SF_PRIVATE *psf)
959 psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ;
960 return SFE_UNIMPLEMENTED ;
961 } /* ogg_vorbis_open */