Made code -Wshadow clean, missed a bunch of issues in the last commit
[supertux.git] / src / audio / ogg_sound_file.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "audio/ogg_sound_file.hpp"
18
19 #include <assert.h>
20
21 OggSoundFile::OggSoundFile(PHYSFS_file* file_, double loop_begin_, double loop_at_) :
22   file(),
23   vorbis_file(),
24   loop_begin(),
25   loop_at(),
26   normal_buffer_loop()
27 {
28   this->file = file_;
29
30   ov_callbacks callbacks = { cb_read, cb_seek, cb_close, cb_tell };
31   ov_open_callbacks(file, &vorbis_file, 0, 0, callbacks);
32
33   vorbis_info* vi = ov_info(&vorbis_file, -1);
34
35   channels        = vi->channels;
36   rate            = vi->rate;
37   bits_per_sample = 16;
38   size            = static_cast<size_t> (ov_pcm_total(&vorbis_file, -1) * 2);
39
40   double samples_begin = loop_begin_ * rate;
41   double sample_loop   = loop_at_ * rate;
42
43   this->loop_begin     = (ogg_int64_t) samples_begin;
44   if(loop_begin_ < 0) {
45     this->loop_at = (ogg_int64_t) -1;
46   } else {
47     this->loop_at = (ogg_int64_t) sample_loop;
48   }
49 }
50
51 OggSoundFile::~OggSoundFile()
52 {
53   ov_clear(&vorbis_file);
54 }
55
56 size_t
57 OggSoundFile::read(void* _buffer, size_t buffer_size)
58 {
59   char*  buffer         = reinterpret_cast<char*> (_buffer);
60   int    section        = 0;
61   size_t totalBytesRead = 0;
62
63   while(buffer_size>0) {
64 #ifdef WORDS_BIGENDIAN
65     int bigendian = 1;
66 #else
67     int bigendian = 0;
68 #endif
69
70     size_t bytes_to_read    = buffer_size;
71     if(loop_at > 0) {
72       size_t      bytes_per_sample       = 2;
73       ogg_int64_t time                   = ov_pcm_tell(&vorbis_file);
74       ogg_int64_t samples_left_till_loop = loop_at - time;
75       ogg_int64_t bytes_left_till_loop
76         = samples_left_till_loop * bytes_per_sample;
77       if(bytes_left_till_loop <= 4)
78         break;
79
80       if(bytes_left_till_loop < (ogg_int64_t) bytes_to_read) {
81         bytes_to_read    = (size_t) bytes_left_till_loop;
82       }
83     }
84
85     long bytesRead
86       = ov_read(&vorbis_file, buffer, bytes_to_read, bigendian,
87                 2, 1, &section);
88     if(bytesRead == 0) {
89       break;
90     }
91     buffer_size    -= bytesRead;
92     buffer         += bytesRead;
93     totalBytesRead += bytesRead;
94   }
95
96   return totalBytesRead;
97 }
98
99 void
100 OggSoundFile::reset()
101 {
102   ov_pcm_seek(&vorbis_file, loop_begin);
103 }
104
105 size_t
106 OggSoundFile::cb_read(void* ptr, size_t size, size_t nmemb, void* source)
107 {
108   PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
109
110   PHYSFS_sint64 res
111     = PHYSFS_read(file, ptr, static_cast<PHYSFS_uint32> (size),
112                   static_cast<PHYSFS_uint32> (nmemb));
113   if(res <= 0)
114     return 0;
115
116   return static_cast<size_t> (res);
117 }
118
119 int
120 OggSoundFile::cb_seek(void* source, ogg_int64_t offset, int whence)
121 {
122   PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
123
124   switch(whence) {
125     case SEEK_SET:
126       if(PHYSFS_seek(file, static_cast<PHYSFS_uint64> (offset)) == 0)
127         return -1;
128       break;
129     case SEEK_CUR:
130       if(PHYSFS_seek(file, PHYSFS_tell(file) + offset) == 0)
131         return -1;
132       break;
133     case SEEK_END:
134       if(PHYSFS_seek(file, PHYSFS_fileLength(file) + offset) == 0)
135         return -1;
136       break;
137     default:
138       assert(false);
139       return -1;
140   }
141   return 0;
142 }
143
144 int
145 OggSoundFile::cb_close(void* source)
146 {
147   PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
148   PHYSFS_close(file);
149   return 0;
150 }
151
152 long
153 OggSoundFile::cb_tell(void* source)
154 {
155   PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
156   return static_cast<long> (PHYSFS_tell(file));
157 }
158
159 /* EOF */