Add support for VFS caching.
[herrie-working.git] / herrie / src / audio_format_vorbis.c
blob614b12ee2b323d55ac956f345c23f566f81889a1
1 /*
2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 /**
27 * @file audio_format_vorbis.c
28 * @brief Ogg Vorbis decompression routines.
31 #include "stdinc.h"
33 #include <vorbis/codec.h>
34 #include <vorbis/vorbisfile.h>
36 #include "audio_file.h"
37 #include "audio_format.h"
38 #include "audio_output.h"
40 /**
41 * @brief Read tags from Ogg Vorbis file and store them in the audio
42 * file handle.
44 static void
45 vorbis_read_comments(struct audio_file *fd)
47 OggVorbis_File *vfp = fd->drv_data;
48 struct vorbis_comment *cmt;
49 int i;
50 const char *tag;
52 if ((cmt = ov_comment(vfp, -1)) == NULL)
53 return;
55 for (i = 0; i < cmt->comments; i++) {
56 tag = cmt->user_comments[i];
58 if (g_ascii_strncasecmp(tag, "artist=", 7) == 0)
59 fd->artist = g_strdup(tag + 7);
60 else if (g_ascii_strncasecmp(tag, "title=", 6) == 0)
61 fd->title = g_strdup(tag + 6);
62 #ifdef BUILD_SCROBBLER
63 else if (g_ascii_strncasecmp(tag, "album=", 6) == 0)
64 fd->album = g_strdup(tag + 6);
65 #endif /* BUILD_SCROBBLER */
69 int
70 vorbis_open(struct audio_file *fd, const char *ext)
72 OggVorbis_File *vfp;
73 vorbis_info *info;
75 if (fd->stream) {
76 /* Not yet */
77 return (-1);
80 vfp = g_slice_new(OggVorbis_File);
81 if (ov_open(fd->fp, vfp, NULL, 0) != 0) {
82 g_slice_free(OggVorbis_File, vfp);
83 return (-1);
86 info = ov_info(vfp, -1);
88 fd->drv_data = vfp;
89 fd->srate = info->rate;
90 fd->channels = 2; /* XXX */
91 fd->time_len = ov_time_total(vfp, -1);
93 vorbis_read_comments(fd);
95 return (0);
98 void
99 vorbis_close(struct audio_file *fd)
101 OggVorbis_File *vfp = fd->drv_data;
103 ov_clear(vfp);
104 g_slice_free(OggVorbis_File, vfp);
106 /* libvorbisfile already closes the file for us */
107 fd->fp = NULL;
110 size_t
111 vorbis_read(struct audio_file *fd, int16_t *buf, size_t len)
113 OggVorbis_File *vfp = fd->drv_data;
114 size_t ret = 0;
115 long rlen;
116 char *out = (char *)buf;
118 len *= sizeof(int16_t);
120 /* Return 16 bits signed native endian */
121 while (ret < len) {
122 #if G_BYTE_ORDER == G_BIG_ENDIAN
123 rlen = ov_read(vfp, out + ret, len - ret, 1, 2, 1, NULL);
124 #else /* G_BYTE_ORDER != G_BIG_ENDIAN */
125 rlen = ov_read(vfp, out + ret, len - ret, 0, 2, 1, NULL);
126 #endif /* G_BYTE_ORDER == G_BIG_ENDIAN */
127 if (rlen <= 0)
128 break;
129 ret += rlen;
131 fd->time_cur = ov_time_tell(vfp);
133 return (ret / sizeof(int16_t));
136 void
137 vorbis_seek(struct audio_file *fd, int len, int rel)
139 double npos;
140 OggVorbis_File *vfp = fd->drv_data;
142 npos = len;
143 if (rel) {
144 /* Perform a relative seek. */
145 npos += ov_time_tell(vfp);
148 npos = CLAMP(npos, 0, ov_time_total(vfp, -1));
150 ov_time_seek(vfp, npos);
151 fd->time_cur = ov_time_tell(vfp);