seal 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (421) hide show
  1. data/.yardopts +1 -0
  2. data/LICENSE +13 -0
  3. data/README.md +265 -0
  4. data/ext/seal/extconf.rb +45 -0
  5. data/include/al/al.h +724 -0
  6. data/include/al/alc.h +277 -0
  7. data/include/al/efx-presets.h +402 -0
  8. data/include/al/efx.h +758 -0
  9. data/include/mpg123/mpg123.h +1034 -0
  10. data/include/ogg/config_types.h +25 -0
  11. data/include/ogg/ogg.h +210 -0
  12. data/include/ogg/os_types.h +147 -0
  13. data/include/seal.h +23 -0
  14. data/include/seal/buf.h +143 -0
  15. data/include/seal/core.h +95 -0
  16. data/include/seal/efs.h +112 -0
  17. data/include/seal/err.h +93 -0
  18. data/include/seal/fmt.h +58 -0
  19. data/include/seal/listener.h +103 -0
  20. data/include/seal/raw.h +86 -0
  21. data/include/seal/rvb.h +520 -0
  22. data/include/seal/src.h +413 -0
  23. data/include/seal/stream.h +81 -0
  24. data/include/vorbis/codec.h +243 -0
  25. data/include/vorbis/vorbisfile.h +206 -0
  26. data/mpg123/AUTHORS +150 -0
  27. data/mpg123/COPYING +773 -0
  28. data/mpg123/ChangeLog +3 -0
  29. data/mpg123/INSTALL +111 -0
  30. data/mpg123/Makefile.am +99 -0
  31. data/mpg123/Makefile.in +1043 -0
  32. data/mpg123/NEWS +1200 -0
  33. data/mpg123/NEWS.libmpg123 +133 -0
  34. data/mpg123/README +203 -0
  35. data/mpg123/TODO +38 -0
  36. data/mpg123/aclocal.m4 +1168 -0
  37. data/mpg123/build/config.guess +1530 -0
  38. data/mpg123/build/config.sub +1782 -0
  39. data/mpg123/build/depcomp +707 -0
  40. data/mpg123/build/install-sh +527 -0
  41. data/mpg123/build/ltmain.sh +9655 -0
  42. data/mpg123/build/missing +330 -0
  43. data/mpg123/configure +20267 -0
  44. data/mpg123/configure.ac +2178 -0
  45. data/mpg123/doc/ACCURACY +2 -0
  46. data/mpg123/doc/BENCHMARKING +110 -0
  47. data/mpg123/doc/BUGS +3 -0
  48. data/mpg123/doc/CONTACT +17 -0
  49. data/mpg123/doc/LICENSE +22 -0
  50. data/mpg123/doc/Makefile.am +32 -0
  51. data/mpg123/doc/Makefile.in +490 -0
  52. data/mpg123/doc/PATENTS +39 -0
  53. data/mpg123/doc/README.3DNOW +56 -0
  54. data/mpg123/doc/README.gain +171 -0
  55. data/mpg123/doc/README.remote +218 -0
  56. data/mpg123/doc/ROAD_TO_LGPL +270 -0
  57. data/mpg123/doc/THANKS +13 -0
  58. data/mpg123/doc/TODO +63 -0
  59. data/mpg123/doc/doxy_examples.c +21 -0
  60. data/mpg123/doc/doxygen.conf +41 -0
  61. data/mpg123/doc/doxyhead.xhtml +12 -0
  62. data/mpg123/doc/examples/dump_seekindex.c +41 -0
  63. data/mpg123/doc/examples/extract_frames.c +92 -0
  64. data/mpg123/doc/examples/feedseek.c +238 -0
  65. data/mpg123/doc/examples/id3dump.c +178 -0
  66. data/mpg123/doc/examples/mpg123_to_wav.c +118 -0
  67. data/mpg123/doc/examples/mpglib.c +92 -0
  68. data/mpg123/doc/examples/scan.c +47 -0
  69. data/mpg123/doc/libmpg123_speed.txt +84 -0
  70. data/mpg123/equalize.dat +37 -0
  71. data/mpg123/libmpg123.pc.in +11 -0
  72. data/mpg123/m4/addrconfig.m4 +34 -0
  73. data/mpg123/m4/libtool.m4 +7982 -0
  74. data/mpg123/m4/ltoptions.m4 +384 -0
  75. data/mpg123/m4/ltsugar.m4 +123 -0
  76. data/mpg123/m4/ltversion.m4 +23 -0
  77. data/mpg123/m4/lt~obsolete.m4 +98 -0
  78. data/mpg123/makedll.sh +19 -0
  79. data/mpg123/man1/mpg123.1 +512 -0
  80. data/mpg123/mpg123.spec +68 -0
  81. data/mpg123/mpg123.spec.in +68 -0
  82. data/mpg123/ports/MSVC++/2005/libmpg123/libmpg123.vcproj +741 -0
  83. data/mpg123/ports/MSVC++/2008/dump_seekindex/dump_seekindex.vcproj +194 -0
  84. data/mpg123/ports/MSVC++/2008/feedseek/feedseek.vcproj +195 -0
  85. data/mpg123/ports/MSVC++/2008/libmpg123/libmpg123.vcproj +1357 -0
  86. data/mpg123/ports/MSVC++/2008/mpg123.sln +44 -0
  87. data/mpg123/ports/MSVC++/2008/mpglib/mpglib.vcproj +191 -0
  88. data/mpg123/ports/MSVC++/2008/scan/scan.vcproj +195 -0
  89. data/mpg123/ports/MSVC++/2008clr/2008clr.sln +81 -0
  90. data/mpg123/ports/MSVC++/2008clr/examples/ReplaceReaderclr/Program.cs +435 -0
  91. data/mpg123/ports/MSVC++/2008clr/examples/ReplaceReaderclr/Properties/AssemblyInfo.cs +36 -0
  92. data/mpg123/ports/MSVC++/2008clr/examples/ReplaceReaderclr/ReplaceReaderclr.csproj +72 -0
  93. data/mpg123/ports/MSVC++/2008clr/examples/feedseekclr/Program.cs +331 -0
  94. data/mpg123/ports/MSVC++/2008clr/examples/feedseekclr/Properties/AssemblyInfo.cs +36 -0
  95. data/mpg123/ports/MSVC++/2008clr/examples/feedseekclr/feedseekclr.csproj +71 -0
  96. data/mpg123/ports/MSVC++/2008clr/examples/scanclr/Program.cs +79 -0
  97. data/mpg123/ports/MSVC++/2008clr/examples/scanclr/Properties/AssemblyInfo.cs +36 -0
  98. data/mpg123/ports/MSVC++/2008clr/examples/scanclr/scanclr.csproj +70 -0
  99. data/mpg123/ports/MSVC++/2008clr/mpg123clr/AssemblyInfo.cpp +76 -0
  100. data/mpg123/ports/MSVC++/2008clr/mpg123clr/ReadMe.txt +165 -0
  101. data/mpg123/ports/MSVC++/2008clr/mpg123clr/advanced.cpp +91 -0
  102. data/mpg123/ports/MSVC++/2008clr/mpg123clr/advanced.h +130 -0
  103. data/mpg123/ports/MSVC++/2008clr/mpg123clr/dllmain.cpp +19 -0
  104. data/mpg123/ports/MSVC++/2008clr/mpg123clr/enum.h +218 -0
  105. data/mpg123/ports/MSVC++/2008clr/mpg123clr/error.cpp +48 -0
  106. data/mpg123/ports/MSVC++/2008clr/mpg123clr/error.h +134 -0
  107. data/mpg123/ports/MSVC++/2008clr/mpg123clr/id3v1.cpp +92 -0
  108. data/mpg123/ports/MSVC++/2008clr/mpg123clr/id3v1.h +132 -0
  109. data/mpg123/ports/MSVC++/2008clr/mpg123clr/id3v2.cpp +138 -0
  110. data/mpg123/ports/MSVC++/2008clr/mpg123clr/id3v2.h +152 -0
  111. data/mpg123/ports/MSVC++/2008clr/mpg123clr/mpg123clr.cpp +896 -0
  112. data/mpg123/ports/MSVC++/2008clr/mpg123clr/mpg123clr.h +953 -0
  113. data/mpg123/ports/MSVC++/2008clr/mpg123clr/mpg123clr.rc +102 -0
  114. data/mpg123/ports/MSVC++/2008clr/mpg123clr/mpg123clr.vcproj +328 -0
  115. data/mpg123/ports/MSVC++/2008clr/mpg123clr/resource.h +14 -0
  116. data/mpg123/ports/MSVC++/2008clr/mpg123clr/stdafx.cpp +8 -0
  117. data/mpg123/ports/MSVC++/2008clr/mpg123clr/stdafx.h +38 -0
  118. data/mpg123/ports/MSVC++/2008clr/mpg123clr/string.cpp +166 -0
  119. data/mpg123/ports/MSVC++/2008clr/mpg123clr/string.h +265 -0
  120. data/mpg123/ports/MSVC++/2008clr/mpg123clr/targetver.h +24 -0
  121. data/mpg123/ports/MSVC++/2008clr/mpg123clr/text.cpp +67 -0
  122. data/mpg123/ports/MSVC++/2008clr/mpg123clr/text.h +111 -0
  123. data/mpg123/ports/MSVC++/2010/dump_seekindex/dump_seekindex.vcxproj +90 -0
  124. data/mpg123/ports/MSVC++/2010/dump_seekindex/dump_seekindex.vcxproj.filters +6 -0
  125. data/mpg123/ports/MSVC++/2010/feedseek/feedseek.vcxproj +95 -0
  126. data/mpg123/ports/MSVC++/2010/feedseek/feedseek.vcxproj.filters +6 -0
  127. data/mpg123/ports/MSVC++/2010/libmpg123/libmpg123.vcxproj +960 -0
  128. data/mpg123/ports/MSVC++/2010/libmpg123/libmpg123.vcxproj.user +3 -0
  129. data/mpg123/ports/MSVC++/2010/libmpg123/yasm.exe +0 -0
  130. data/mpg123/ports/MSVC++/2010/mpg123.sln +38 -0
  131. data/mpg123/ports/MSVC++/2010/scan/scan.vcxproj +93 -0
  132. data/mpg123/ports/MSVC++/2010/scan/scan.vcxproj.filters +6 -0
  133. data/mpg123/ports/MSVC++/CMP3Stream/INCLUDE/CORE/CORE_FileIn.H +15 -0
  134. data/mpg123/ports/MSVC++/CMP3Stream/INCLUDE/CORE/SourceFilter_MP3.H +139 -0
  135. data/mpg123/ports/MSVC++/CMP3Stream/INCLUDE/IIEP_Def.H +206 -0
  136. data/mpg123/ports/MSVC++/CMP3Stream/INCLUDE/IIEP_FileIn.H +167 -0
  137. data/mpg123/ports/MSVC++/CMP3Stream/README +4 -0
  138. data/mpg123/ports/MSVC++/CMP3Stream/SOURCE/CORE_FileIn.CPP +462 -0
  139. data/mpg123/ports/MSVC++/CMP3Stream/SOURCE/CORE_Log.CPP +122 -0
  140. data/mpg123/ports/MSVC++/CMP3Stream/SOURCE/CORE_Mutex.CPP +35 -0
  141. data/mpg123/ports/MSVC++/CMP3Stream/SOURCE/SourceFilter_MP3Stream.CPP +586 -0
  142. data/mpg123/ports/MSVC++/CMP3Stream/libMPG123/PLACE_LIBMPG123_SOURCES_HERE +0 -0
  143. data/mpg123/ports/MSVC++/CMP3Stream/libMPG123/libMPG123.vcproj +245 -0
  144. data/mpg123/ports/MSVC++/config.h +35 -0
  145. data/mpg123/ports/MSVC++/examples/feedseek.c +240 -0
  146. data/mpg123/ports/MSVC++/examples/scan.c +47 -0
  147. data/mpg123/ports/MSVC++/mpg123.h +46 -0
  148. data/mpg123/ports/MSVC++/msvc.c +59 -0
  149. data/mpg123/ports/README +26 -0
  150. data/mpg123/ports/Sony_PSP/Makefile.psp +38 -0
  151. data/mpg123/ports/Sony_PSP/README +11 -0
  152. data/mpg123/ports/Sony_PSP/config.h +368 -0
  153. data/mpg123/ports/Sony_PSP/readers.c.patch +2 -0
  154. data/mpg123/ports/Xcode/config.h +197 -0
  155. data/mpg123/ports/Xcode/mpg123.h +17 -0
  156. data/mpg123/ports/Xcode/mpg123.xcodeproj/project.pbxproj +670 -0
  157. data/mpg123/ports/mpg123_.pas +478 -0
  158. data/mpg123/scripts/benchmark-cpu.pl +56 -0
  159. data/mpg123/scripts/tag_lyrics.py +76 -0
  160. data/mpg123/src/Makefile.am +186 -0
  161. data/mpg123/src/Makefile.in +1097 -0
  162. data/mpg123/src/audio.c +725 -0
  163. data/mpg123/src/audio.h +106 -0
  164. data/mpg123/src/buffer.c +312 -0
  165. data/mpg123/src/buffer.h +45 -0
  166. data/mpg123/src/common.c +240 -0
  167. data/mpg123/src/common.h +29 -0
  168. data/mpg123/src/config.h.in +436 -0
  169. data/mpg123/src/control_generic.c +809 -0
  170. data/mpg123/src/equalizer.c +48 -0
  171. data/mpg123/src/genre.c +271 -0
  172. data/mpg123/src/genre.h +15 -0
  173. data/mpg123/src/getlopt.c +148 -0
  174. data/mpg123/src/getlopt.h +77 -0
  175. data/mpg123/src/httpget.c +700 -0
  176. data/mpg123/src/httpget.h +66 -0
  177. data/mpg123/src/legacy_module.c +74 -0
  178. data/mpg123/src/libmpg123/Makefile.am +141 -0
  179. data/mpg123/src/libmpg123/Makefile.in +919 -0
  180. data/mpg123/src/libmpg123/compat.c +138 -0
  181. data/mpg123/src/libmpg123/compat.h +178 -0
  182. data/mpg123/src/libmpg123/dct36_3dnow.S +505 -0
  183. data/mpg123/src/libmpg123/dct36_3dnowext.S +512 -0
  184. data/mpg123/src/libmpg123/dct64.c +174 -0
  185. data/mpg123/src/libmpg123/dct64_3dnow.S +712 -0
  186. data/mpg123/src/libmpg123/dct64_3dnowext.S +714 -0
  187. data/mpg123/src/libmpg123/dct64_altivec.c +315 -0
  188. data/mpg123/src/libmpg123/dct64_i386.c +336 -0
  189. data/mpg123/src/libmpg123/dct64_i486.c +342 -0
  190. data/mpg123/src/libmpg123/dct64_mmx.S +811 -0
  191. data/mpg123/src/libmpg123/dct64_neon.S +297 -0
  192. data/mpg123/src/libmpg123/dct64_neon_float.S +270 -0
  193. data/mpg123/src/libmpg123/dct64_sse.S +454 -0
  194. data/mpg123/src/libmpg123/dct64_sse_float.S +401 -0
  195. data/mpg123/src/libmpg123/dct64_x86_64.S +464 -0
  196. data/mpg123/src/libmpg123/dct64_x86_64_float.S +426 -0
  197. data/mpg123/src/libmpg123/debug.h +171 -0
  198. data/mpg123/src/libmpg123/decode.h +268 -0
  199. data/mpg123/src/libmpg123/dither.c +119 -0
  200. data/mpg123/src/libmpg123/dither.h +23 -0
  201. data/mpg123/src/libmpg123/equalizer.c +17 -0
  202. data/mpg123/src/libmpg123/equalizer_3dnow.S +70 -0
  203. data/mpg123/src/libmpg123/feature.c +106 -0
  204. data/mpg123/src/libmpg123/format.c +521 -0
  205. data/mpg123/src/libmpg123/frame.c +1046 -0
  206. data/mpg123/src/libmpg123/frame.h +410 -0
  207. data/mpg123/src/libmpg123/gapless.h +119 -0
  208. data/mpg123/src/libmpg123/getbits.h +100 -0
  209. data/mpg123/src/libmpg123/getcpuflags.S +91 -0
  210. data/mpg123/src/libmpg123/getcpuflags.h +47 -0
  211. data/mpg123/src/libmpg123/huffman.h +340 -0
  212. data/mpg123/src/libmpg123/icy.c +32 -0
  213. data/mpg123/src/libmpg123/icy.h +38 -0
  214. data/mpg123/src/libmpg123/icy2utf8.c +438 -0
  215. data/mpg123/src/libmpg123/icy2utf8.h +10 -0
  216. data/mpg123/src/libmpg123/id3.c +999 -0
  217. data/mpg123/src/libmpg123/id3.h +43 -0
  218. data/mpg123/src/libmpg123/index.c +134 -0
  219. data/mpg123/src/libmpg123/index.h +59 -0
  220. data/mpg123/src/libmpg123/intsym.h +256 -0
  221. data/mpg123/src/libmpg123/l12_integer_tables.h +278 -0
  222. data/mpg123/src/libmpg123/l2tables.h +164 -0
  223. data/mpg123/src/libmpg123/l3_integer_tables.h +1002 -0
  224. data/mpg123/src/libmpg123/layer1.c +155 -0
  225. data/mpg123/src/libmpg123/layer2.c +371 -0
  226. data/mpg123/src/libmpg123/layer3.c +2053 -0
  227. data/mpg123/src/libmpg123/lfs_alias.c +252 -0
  228. data/mpg123/src/libmpg123/lfs_wrap.c +751 -0
  229. data/mpg123/src/libmpg123/libmpg123.c +1607 -0
  230. data/mpg123/src/libmpg123/mangle.h +74 -0
  231. data/mpg123/src/libmpg123/mpeghead.h +87 -0
  232. data/mpg123/src/libmpg123/mpg123.h.in +1075 -0
  233. data/mpg123/src/libmpg123/mpg123lib_intern.h +338 -0
  234. data/mpg123/src/libmpg123/ntom.c +148 -0
  235. data/mpg123/src/libmpg123/optimize.c +964 -0
  236. data/mpg123/src/libmpg123/optimize.h +219 -0
  237. data/mpg123/src/libmpg123/parse.c +1179 -0
  238. data/mpg123/src/libmpg123/parse.h +25 -0
  239. data/mpg123/src/libmpg123/reader.h +137 -0
  240. data/mpg123/src/libmpg123/readers.c +1235 -0
  241. data/mpg123/src/libmpg123/sample.h +152 -0
  242. data/mpg123/src/libmpg123/stringbuf.c +163 -0
  243. data/mpg123/src/libmpg123/synth.c +816 -0
  244. data/mpg123/src/libmpg123/synth.h +196 -0
  245. data/mpg123/src/libmpg123/synth_3dnow.S +318 -0
  246. data/mpg123/src/libmpg123/synth_3dnowext.S +6 -0
  247. data/mpg123/src/libmpg123/synth_8bit.c +142 -0
  248. data/mpg123/src/libmpg123/synth_8bit.h +86 -0
  249. data/mpg123/src/libmpg123/synth_altivec.c +1057 -0
  250. data/mpg123/src/libmpg123/synth_arm.S +271 -0
  251. data/mpg123/src/libmpg123/synth_arm_accurate.S +287 -0
  252. data/mpg123/src/libmpg123/synth_i486.c +252 -0
  253. data/mpg123/src/libmpg123/synth_i586.S +336 -0
  254. data/mpg123/src/libmpg123/synth_i586_dither.S +375 -0
  255. data/mpg123/src/libmpg123/synth_mmx.S +125 -0
  256. data/mpg123/src/libmpg123/synth_mono.h +64 -0
  257. data/mpg123/src/libmpg123/synth_neon.S +123 -0
  258. data/mpg123/src/libmpg123/synth_neon_accurate.S +173 -0
  259. data/mpg123/src/libmpg123/synth_neon_float.S +149 -0
  260. data/mpg123/src/libmpg123/synth_neon_s32.S +168 -0
  261. data/mpg123/src/libmpg123/synth_ntom.h +213 -0
  262. data/mpg123/src/libmpg123/synth_real.c +404 -0
  263. data/mpg123/src/libmpg123/synth_s32.c +411 -0
  264. data/mpg123/src/libmpg123/synth_sse.S +6 -0
  265. data/mpg123/src/libmpg123/synth_sse3d.h +246 -0
  266. data/mpg123/src/libmpg123/synth_sse_accurate.S +294 -0
  267. data/mpg123/src/libmpg123/synth_sse_float.S +241 -0
  268. data/mpg123/src/libmpg123/synth_sse_s32.S +306 -0
  269. data/mpg123/src/libmpg123/synth_stereo_neon.S +175 -0
  270. data/mpg123/src/libmpg123/synth_stereo_neon_accurate.S +262 -0
  271. data/mpg123/src/libmpg123/synth_stereo_neon_float.S +220 -0
  272. data/mpg123/src/libmpg123/synth_stereo_neon_s32.S +247 -0
  273. data/mpg123/src/libmpg123/synth_stereo_sse_accurate.S +508 -0
  274. data/mpg123/src/libmpg123/synth_stereo_sse_float.S +416 -0
  275. data/mpg123/src/libmpg123/synth_stereo_sse_s32.S +540 -0
  276. data/mpg123/src/libmpg123/synth_stereo_x86_64.S +335 -0
  277. data/mpg123/src/libmpg123/synth_stereo_x86_64_accurate.S +454 -0
  278. data/mpg123/src/libmpg123/synth_stereo_x86_64_float.S +396 -0
  279. data/mpg123/src/libmpg123/synth_stereo_x86_64_s32.S +473 -0
  280. data/mpg123/src/libmpg123/synth_x86_64.S +244 -0
  281. data/mpg123/src/libmpg123/synth_x86_64_accurate.S +301 -0
  282. data/mpg123/src/libmpg123/synth_x86_64_float.S +259 -0
  283. data/mpg123/src/libmpg123/synth_x86_64_s32.S +312 -0
  284. data/mpg123/src/libmpg123/synths.h +52 -0
  285. data/mpg123/src/libmpg123/tabinit.c +294 -0
  286. data/mpg123/src/libmpg123/tabinit_mmx.S +210 -0
  287. data/mpg123/src/libmpg123/testcpu.c +35 -0
  288. data/mpg123/src/libmpg123/true.h +14 -0
  289. data/mpg123/src/local.c +63 -0
  290. data/mpg123/src/local.h +21 -0
  291. data/mpg123/src/metaprint.c +373 -0
  292. data/mpg123/src/metaprint.h +17 -0
  293. data/mpg123/src/module.c +306 -0
  294. data/mpg123/src/module.h +48 -0
  295. data/mpg123/src/mpg123.c +1405 -0
  296. data/mpg123/src/mpg123app.h +171 -0
  297. data/mpg123/src/output/Makefile.am +213 -0
  298. data/mpg123/src/output/Makefile.in +1238 -0
  299. data/mpg123/src/output/aix.c +300 -0
  300. data/mpg123/src/output/alib.c +209 -0
  301. data/mpg123/src/output/alsa.c +297 -0
  302. data/mpg123/src/output/arts.c +117 -0
  303. data/mpg123/src/output/coreaudio.c +370 -0
  304. data/mpg123/src/output/dummy.c +78 -0
  305. data/mpg123/src/output/esd.c +167 -0
  306. data/mpg123/src/output/hp.c +184 -0
  307. data/mpg123/src/output/jack.c +450 -0
  308. data/mpg123/src/output/mint.c +197 -0
  309. data/mpg123/src/output/nas.c +335 -0
  310. data/mpg123/src/output/openal.c +197 -0
  311. data/mpg123/src/output/os2.c +665 -0
  312. data/mpg123/src/output/oss.c +319 -0
  313. data/mpg123/src/output/portaudio.c +255 -0
  314. data/mpg123/src/output/pulse.c +164 -0
  315. data/mpg123/src/output/sdl.c +206 -0
  316. data/mpg123/src/output/sgi.c +213 -0
  317. data/mpg123/src/output/sndio.c +161 -0
  318. data/mpg123/src/output/sun.c +281 -0
  319. data/mpg123/src/output/win32.c +229 -0
  320. data/mpg123/src/playlist.c +596 -0
  321. data/mpg123/src/playlist.h +52 -0
  322. data/mpg123/src/resolver.c +319 -0
  323. data/mpg123/src/resolver.h +25 -0
  324. data/mpg123/src/sfifo.c +146 -0
  325. data/mpg123/src/sfifo.h +95 -0
  326. data/mpg123/src/streamdump.c +74 -0
  327. data/mpg123/src/streamdump.h +20 -0
  328. data/mpg123/src/term.c +479 -0
  329. data/mpg123/src/term.h +81 -0
  330. data/mpg123/src/tests/noise.c +52 -0
  331. data/mpg123/src/tests/plain_id3.c +109 -0
  332. data/mpg123/src/tests/seek_accuracy.c +261 -0
  333. data/mpg123/src/tests/seek_whence.c +56 -0
  334. data/mpg123/src/tests/testtext.h +34 -0
  335. data/mpg123/src/tests/text.c +80 -0
  336. data/mpg123/src/wav.c +464 -0
  337. data/mpg123/src/wavhead.h +68 -0
  338. data/mpg123/src/win32_net.c +599 -0
  339. data/mpg123/src/win32_support.c +191 -0
  340. data/mpg123/src/win32_support.h +152 -0
  341. data/mpg123/src/xfermem.c +321 -0
  342. data/mpg123/src/xfermem.h +74 -0
  343. data/mpg123/windows-builds.sh +137 -0
  344. data/msvc/lib/OpenAL32.lib +0 -0
  345. data/spec/fixtures/heal.ogg +0 -0
  346. data/spec/fixtures/tone_up.wav +0 -0
  347. data/spec/seal/buffer_spec.rb +37 -0
  348. data/spec/seal/core_spec.rb +29 -0
  349. data/spec/seal/effect_slot_spec.rb +38 -0
  350. data/spec/seal/listener_spec.rb +33 -0
  351. data/spec/seal/reverb_spec.rb +51 -0
  352. data/spec/seal/source_spec.rb +370 -0
  353. data/spec/seal/stream_spec.rb +38 -0
  354. data/spec/spec_helper.rb +45 -0
  355. data/spec/support/attribute_examples.rb +75 -0
  356. data/spec/support/audio_object_with_format.rb +27 -0
  357. data/spec/support/movable_object.rb +22 -0
  358. data/src/libogg/bitwise.c +857 -0
  359. data/src/libogg/framing.c +2093 -0
  360. data/src/libvorbis/backends.h +144 -0
  361. data/src/libvorbis/bitrate.c +253 -0
  362. data/src/libvorbis/bitrate.h +59 -0
  363. data/src/libvorbis/block.c +1046 -0
  364. data/src/libvorbis/codebook.c +484 -0
  365. data/src/libvorbis/codebook.h +119 -0
  366. data/src/libvorbis/codec_internal.h +167 -0
  367. data/src/libvorbis/envelope.c +375 -0
  368. data/src/libvorbis/envelope.h +80 -0
  369. data/src/libvorbis/floor0.c +221 -0
  370. data/src/libvorbis/floor1.c +1100 -0
  371. data/src/libvorbis/highlevel.h +58 -0
  372. data/src/libvorbis/info.c +668 -0
  373. data/src/libvorbis/lookup.c +94 -0
  374. data/src/libvorbis/lookup.h +32 -0
  375. data/src/libvorbis/lookup_data.h +192 -0
  376. data/src/libvorbis/lpc.c +160 -0
  377. data/src/libvorbis/lpc.h +29 -0
  378. data/src/libvorbis/lsp.c +456 -0
  379. data/src/libvorbis/lsp.h +28 -0
  380. data/src/libvorbis/mapping0.c +816 -0
  381. data/src/libvorbis/masking.h +785 -0
  382. data/src/libvorbis/mdct.c +563 -0
  383. data/src/libvorbis/mdct.h +71 -0
  384. data/src/libvorbis/misc.h +57 -0
  385. data/src/libvorbis/os.h +186 -0
  386. data/src/libvorbis/psy.c +1206 -0
  387. data/src/libvorbis/psy.h +154 -0
  388. data/src/libvorbis/registry.c +45 -0
  389. data/src/libvorbis/registry.h +32 -0
  390. data/src/libvorbis/res0.c +889 -0
  391. data/src/libvorbis/scales.h +90 -0
  392. data/src/libvorbis/sharedbook.c +579 -0
  393. data/src/libvorbis/smallft.c +1255 -0
  394. data/src/libvorbis/smallft.h +34 -0
  395. data/src/libvorbis/synthesis.c +184 -0
  396. data/src/libvorbis/vorbisfile.c +2337 -0
  397. data/src/libvorbis/window.c +2135 -0
  398. data/src/libvorbis/window.h +26 -0
  399. data/src/rubyext.c +2329 -0
  400. data/src/seal/buf.c +124 -0
  401. data/src/seal/core.c +283 -0
  402. data/src/seal/efs.c +74 -0
  403. data/src/seal/err.c +118 -0
  404. data/src/seal/fmt.c +86 -0
  405. data/src/seal/listener.c +111 -0
  406. data/src/seal/mpg.c +174 -0
  407. data/src/seal/mpg.h +24 -0
  408. data/src/seal/ov.c +180 -0
  409. data/src/seal/ov.h +22 -0
  410. data/src/seal/raw.c +59 -0
  411. data/src/seal/reader.c +102 -0
  412. data/src/seal/reader.h +59 -0
  413. data/src/seal/rvb.c +368 -0
  414. data/src/seal/src.c +654 -0
  415. data/src/seal/stream.c +109 -0
  416. data/src/seal/threading.c +66 -0
  417. data/src/seal/threading.h +20 -0
  418. data/src/seal/wav.c +297 -0
  419. data/src/seal/wav.h +23 -0
  420. data/src/win32api.rb +29 -0
  421. metadata +563 -0
@@ -0,0 +1,34 @@
1
+ /********************************************************************
2
+ * *
3
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7
+ * *
8
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
9
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
10
+ * *
11
+ ********************************************************************
12
+
13
+ function: fft transform
14
+ last mod: $Id: smallft.h 13293 2007-07-24 00:09:47Z xiphmont $
15
+
16
+ ********************************************************************/
17
+
18
+ #ifndef _V_SMFT_H_
19
+ #define _V_SMFT_H_
20
+
21
+ #include "vorbis/codec.h"
22
+
23
+ typedef struct {
24
+ int n;
25
+ float *trigcache;
26
+ int *splitcache;
27
+ } drft_lookup;
28
+
29
+ extern void drft_forward(drft_lookup *l,float *data);
30
+ extern void drft_backward(drft_lookup *l,float *data);
31
+ extern void drft_init(drft_lookup *l,int n);
32
+ extern void drft_clear(drft_lookup *l);
33
+
34
+ #endif
@@ -0,0 +1,184 @@
1
+ /********************************************************************
2
+ * *
3
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7
+ * *
8
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
9
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
10
+ * *
11
+ ********************************************************************
12
+
13
+ function: single-block PCM synthesis
14
+ last mod: $Id: synthesis.c 17474 2010-09-30 03:41:41Z gmaxwell $
15
+
16
+ ********************************************************************/
17
+
18
+ #include <stdio.h>
19
+ #include <ogg/ogg.h>
20
+ #include "vorbis/codec.h"
21
+ #include "codec_internal.h"
22
+ #include "registry.h"
23
+ #include "misc.h"
24
+ #include "os.h"
25
+
26
+ int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){
27
+ vorbis_dsp_state *vd= vb ? vb->vd : 0;
28
+ private_state *b= vd ? vd->backend_state : 0;
29
+ vorbis_info *vi= vd ? vd->vi : 0;
30
+ codec_setup_info *ci= vi ? vi->codec_setup : 0;
31
+ oggpack_buffer *opb=vb ? &vb->opb : 0;
32
+ int type,mode,i;
33
+
34
+ if (!vd || !b || !vi || !ci || !opb) {
35
+ return OV_EBADPACKET;
36
+ }
37
+
38
+ /* first things first. Make sure decode is ready */
39
+ _vorbis_block_ripcord(vb);
40
+ oggpack_readinit(opb,op->packet,op->bytes);
41
+
42
+ /* Check the packet type */
43
+ if(oggpack_read(opb,1)!=0){
44
+ /* Oops. This is not an audio data packet */
45
+ return(OV_ENOTAUDIO);
46
+ }
47
+
48
+ /* read our mode and pre/post windowsize */
49
+ mode=oggpack_read(opb,b->modebits);
50
+ if(mode==-1){
51
+ return(OV_EBADPACKET);
52
+ }
53
+
54
+ vb->mode=mode;
55
+ if(!ci->mode_param[mode]){
56
+ return(OV_EBADPACKET);
57
+ }
58
+
59
+ vb->W=ci->mode_param[mode]->blockflag;
60
+ if(vb->W){
61
+
62
+ /* this doesn;t get mapped through mode selection as it's used
63
+ only for window selection */
64
+ vb->lW=oggpack_read(opb,1);
65
+ vb->nW=oggpack_read(opb,1);
66
+ if(vb->nW==-1){
67
+ return(OV_EBADPACKET);
68
+ }
69
+ }else{
70
+ vb->lW=0;
71
+ vb->nW=0;
72
+ }
73
+
74
+ /* more setup */
75
+ vb->granulepos=op->granulepos;
76
+ vb->sequence=op->packetno;
77
+ vb->eofflag=op->e_o_s;
78
+
79
+ /* alloc pcm passback storage */
80
+ vb->pcmend=ci->blocksizes[vb->W];
81
+ vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
82
+ for(i=0;i<vi->channels;i++)
83
+ vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
84
+
85
+ /* unpack_header enforces range checking */
86
+ type=ci->map_type[ci->mode_param[mode]->mapping];
87
+
88
+ return(_mapping_P[type]->inverse(vb,ci->map_param[ci->mode_param[mode]->
89
+ mapping]));
90
+ }
91
+
92
+ /* used to track pcm position without actually performing decode.
93
+ Useful for sequential 'fast forward' */
94
+ int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){
95
+ vorbis_dsp_state *vd=vb->vd;
96
+ private_state *b=vd->backend_state;
97
+ vorbis_info *vi=vd->vi;
98
+ codec_setup_info *ci=vi->codec_setup;
99
+ oggpack_buffer *opb=&vb->opb;
100
+ int mode;
101
+
102
+ /* first things first. Make sure decode is ready */
103
+ _vorbis_block_ripcord(vb);
104
+ oggpack_readinit(opb,op->packet,op->bytes);
105
+
106
+ /* Check the packet type */
107
+ if(oggpack_read(opb,1)!=0){
108
+ /* Oops. This is not an audio data packet */
109
+ return(OV_ENOTAUDIO);
110
+ }
111
+
112
+ /* read our mode and pre/post windowsize */
113
+ mode=oggpack_read(opb,b->modebits);
114
+ if(mode==-1)return(OV_EBADPACKET);
115
+
116
+ vb->mode=mode;
117
+ if(!ci->mode_param[mode]){
118
+ return(OV_EBADPACKET);
119
+ }
120
+
121
+ vb->W=ci->mode_param[mode]->blockflag;
122
+ if(vb->W){
123
+ vb->lW=oggpack_read(opb,1);
124
+ vb->nW=oggpack_read(opb,1);
125
+ if(vb->nW==-1) return(OV_EBADPACKET);
126
+ }else{
127
+ vb->lW=0;
128
+ vb->nW=0;
129
+ }
130
+
131
+ /* more setup */
132
+ vb->granulepos=op->granulepos;
133
+ vb->sequence=op->packetno;
134
+ vb->eofflag=op->e_o_s;
135
+
136
+ /* no pcm */
137
+ vb->pcmend=0;
138
+ vb->pcm=NULL;
139
+
140
+ return(0);
141
+ }
142
+
143
+ long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
144
+ codec_setup_info *ci=vi->codec_setup;
145
+ oggpack_buffer opb;
146
+ int mode;
147
+
148
+ oggpack_readinit(&opb,op->packet,op->bytes);
149
+
150
+ /* Check the packet type */
151
+ if(oggpack_read(&opb,1)!=0){
152
+ /* Oops. This is not an audio data packet */
153
+ return(OV_ENOTAUDIO);
154
+ }
155
+
156
+ {
157
+ int modebits=0;
158
+ int v=ci->modes;
159
+ while(v>1){
160
+ modebits++;
161
+ v>>=1;
162
+ }
163
+
164
+ /* read our mode and pre/post windowsize */
165
+ mode=oggpack_read(&opb,modebits);
166
+ }
167
+ if(mode==-1)return(OV_EBADPACKET);
168
+ return(ci->blocksizes[ci->mode_param[mode]->blockflag]);
169
+ }
170
+
171
+ int vorbis_synthesis_halfrate(vorbis_info *vi,int flag){
172
+ /* set / clear half-sample-rate mode */
173
+ codec_setup_info *ci=vi->codec_setup;
174
+
175
+ /* right now, our MDCT can't handle < 64 sample windows. */
176
+ if(ci->blocksizes[0]<=64 && flag)return -1;
177
+ ci->halfrate_flag=(flag?1:0);
178
+ return 0;
179
+ }
180
+
181
+ int vorbis_synthesis_halfrate_p(vorbis_info *vi){
182
+ codec_setup_info *ci=vi->codec_setup;
183
+ return ci->halfrate_flag;
184
+ }
@@ -0,0 +1,2337 @@
1
+ /********************************************************************
2
+ * *
3
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7
+ * *
8
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
9
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
10
+ * *
11
+ ********************************************************************
12
+
13
+ function: stdio-based convenience library for opening/seeking/decoding
14
+ last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
15
+
16
+ ********************************************************************/
17
+
18
+ #include <stdlib.h>
19
+ #include <stdio.h>
20
+ #include <errno.h>
21
+ #include <string.h>
22
+ #include <math.h>
23
+
24
+ #include "vorbis/codec.h"
25
+
26
+ /* we don't need or want the static callback symbols here */
27
+ #define OV_EXCLUDE_STATIC_CALLBACKS
28
+ #include "vorbis/vorbisfile.h"
29
+
30
+ #include "os.h"
31
+ #include "misc.h"
32
+
33
+ /* A 'chained bitstream' is a Vorbis bitstream that contains more than
34
+ one logical bitstream arranged end to end (the only form of Ogg
35
+ multiplexing allowed in a Vorbis bitstream; grouping [parallel
36
+ multiplexing] is not allowed in Vorbis) */
37
+
38
+ /* A Vorbis file can be played beginning to end (streamed) without
39
+ worrying ahead of time about chaining (see decoder_example.c). If
40
+ we have the whole file, however, and want random access
41
+ (seeking/scrubbing) or desire to know the total length/time of a
42
+ file, we need to account for the possibility of chaining. */
43
+
44
+ /* We can handle things a number of ways; we can determine the entire
45
+ bitstream structure right off the bat, or find pieces on demand.
46
+ This example determines and caches structure for the entire
47
+ bitstream, but builds a virtual decoder on the fly when moving
48
+ between links in the chain. */
49
+
50
+ /* There are also different ways to implement seeking. Enough
51
+ information exists in an Ogg bitstream to seek to
52
+ sample-granularity positions in the output. Or, one can seek by
53
+ picking some portion of the stream roughly in the desired area if
54
+ we only want coarse navigation through the stream. */
55
+
56
+ /*************************************************************************
57
+ * Many, many internal helpers. The intention is not to be confusing;
58
+ * rampant duplication and monolithic function implementation would be
59
+ * harder to understand anyway. The high level functions are last. Begin
60
+ * grokking near the end of the file */
61
+
62
+ /* read a little more data from the file/pipe into the ogg_sync framer
63
+ */
64
+ #define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */
65
+ #define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */
66
+
67
+ static long _get_data(OggVorbis_File *vf){
68
+ errno=0;
69
+ if(!(vf->callbacks.read_func))return(-1);
70
+ if(vf->datasource){
71
+ char *buffer=ogg_sync_buffer(&vf->oy,READSIZE);
72
+ long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource);
73
+ if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
74
+ if(bytes==0 && errno)return(-1);
75
+ return(bytes);
76
+ }else
77
+ return(0);
78
+ }
79
+
80
+ /* save a tiny smidge of verbosity to make the code more readable */
81
+ static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
82
+ if(vf->datasource){
83
+ if(!(vf->callbacks.seek_func)||
84
+ (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
85
+ return OV_EREAD;
86
+ vf->offset=offset;
87
+ ogg_sync_reset(&vf->oy);
88
+ }else{
89
+ /* shouldn't happen unless someone writes a broken callback */
90
+ return OV_EFAULT;
91
+ }
92
+ return 0;
93
+ }
94
+
95
+ /* The read/seek functions track absolute position within the stream */
96
+
97
+ /* from the head of the stream, get the next page. boundary specifies
98
+ if the function is allowed to fetch more data from the stream (and
99
+ how much) or only use internally buffered data.
100
+
101
+ boundary: -1) unbounded search
102
+ 0) read no additional data; use cached only
103
+ n) search for a new page beginning for n bytes
104
+
105
+ return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
106
+ n) found a page at absolute offset n */
107
+
108
+ static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
109
+ ogg_int64_t boundary){
110
+ if(boundary>0)boundary+=vf->offset;
111
+ while(1){
112
+ long more;
113
+
114
+ if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
115
+ more=ogg_sync_pageseek(&vf->oy,og);
116
+
117
+ if(more<0){
118
+ /* skipped n bytes */
119
+ vf->offset-=more;
120
+ }else{
121
+ if(more==0){
122
+ /* send more paramedics */
123
+ if(!boundary)return(OV_FALSE);
124
+ {
125
+ long ret=_get_data(vf);
126
+ if(ret==0)return(OV_EOF);
127
+ if(ret<0)return(OV_EREAD);
128
+ }
129
+ }else{
130
+ /* got a page. Return the offset at the page beginning,
131
+ advance the internal offset past the page end */
132
+ ogg_int64_t ret=vf->offset;
133
+ vf->offset+=more;
134
+ return(ret);
135
+
136
+ }
137
+ }
138
+ }
139
+ }
140
+
141
+ /* find the latest page beginning before the current stream cursor
142
+ position. Much dirtier than the above as Ogg doesn't have any
143
+ backward search linkage. no 'readp' as it will certainly have to
144
+ read. */
145
+ /* returns offset or OV_EREAD, OV_FAULT */
146
+ static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
147
+ ogg_int64_t begin=vf->offset;
148
+ ogg_int64_t end=begin;
149
+ ogg_int64_t ret;
150
+ ogg_int64_t offset=-1;
151
+
152
+ while(offset==-1){
153
+ begin-=CHUNKSIZE;
154
+ if(begin<0)
155
+ begin=0;
156
+
157
+ ret=_seek_helper(vf,begin);
158
+ if(ret)return(ret);
159
+
160
+ while(vf->offset<end){
161
+ memset(og,0,sizeof(*og));
162
+ ret=_get_next_page(vf,og,end-vf->offset);
163
+ if(ret==OV_EREAD)return(OV_EREAD);
164
+ if(ret<0){
165
+ break;
166
+ }else{
167
+ offset=ret;
168
+ }
169
+ }
170
+ }
171
+
172
+ /* In a fully compliant, non-multiplexed stream, we'll still be
173
+ holding the last page. In multiplexed (or noncompliant streams),
174
+ we will probably have to re-read the last page we saw */
175
+ if(og->header_len==0){
176
+ ret=_seek_helper(vf,offset);
177
+ if(ret)return(ret);
178
+
179
+ ret=_get_next_page(vf,og,CHUNKSIZE);
180
+ if(ret<0)
181
+ /* this shouldn't be possible */
182
+ return(OV_EFAULT);
183
+ }
184
+
185
+ return(offset);
186
+ }
187
+
188
+ static void _add_serialno(ogg_page *og,long **serialno_list, int *n){
189
+ long s = ogg_page_serialno(og);
190
+ (*n)++;
191
+
192
+ if(*serialno_list){
193
+ *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n));
194
+ }else{
195
+ *serialno_list = _ogg_malloc(sizeof(**serialno_list));
196
+ }
197
+
198
+ (*serialno_list)[(*n)-1] = s;
199
+ }
200
+
201
+ /* returns nonzero if found */
202
+ static int _lookup_serialno(long s, long *serialno_list, int n){
203
+ if(serialno_list){
204
+ while(n--){
205
+ if(*serialno_list == s) return 1;
206
+ serialno_list++;
207
+ }
208
+ }
209
+ return 0;
210
+ }
211
+
212
+ static int _lookup_page_serialno(ogg_page *og, long *serialno_list, int n){
213
+ long s = ogg_page_serialno(og);
214
+ return _lookup_serialno(s,serialno_list,n);
215
+ }
216
+
217
+ /* performs the same search as _get_prev_page, but prefers pages of
218
+ the specified serial number. If a page of the specified serialno is
219
+ spotted during the seek-back-and-read-forward, it will return the
220
+ info of last page of the matching serial number instead of the very
221
+ last page. If no page of the specified serialno is seen, it will
222
+ return the info of last page and alter *serialno. */
223
+ static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf,
224
+ long *serial_list, int serial_n,
225
+ int *serialno, ogg_int64_t *granpos){
226
+ ogg_page og;
227
+ ogg_int64_t begin=vf->offset;
228
+ ogg_int64_t end=begin;
229
+ ogg_int64_t ret;
230
+
231
+ ogg_int64_t prefoffset=-1;
232
+ ogg_int64_t offset=-1;
233
+ ogg_int64_t ret_serialno=-1;
234
+ ogg_int64_t ret_gran=-1;
235
+
236
+ while(offset==-1){
237
+ begin-=CHUNKSIZE;
238
+ if(begin<0)
239
+ begin=0;
240
+
241
+ ret=_seek_helper(vf,begin);
242
+ if(ret)return(ret);
243
+
244
+ while(vf->offset<end){
245
+ ret=_get_next_page(vf,&og,end-vf->offset);
246
+ if(ret==OV_EREAD)return(OV_EREAD);
247
+ if(ret<0){
248
+ break;
249
+ }else{
250
+ ret_serialno=ogg_page_serialno(&og);
251
+ ret_gran=ogg_page_granulepos(&og);
252
+ offset=ret;
253
+
254
+ if(ret_serialno == *serialno){
255
+ prefoffset=ret;
256
+ *granpos=ret_gran;
257
+ }
258
+
259
+ if(!_lookup_serialno(ret_serialno,serial_list,serial_n)){
260
+ /* we fell off the end of the link, which means we seeked
261
+ back too far and shouldn't have been looking in that link
262
+ to begin with. If we found the preferred serial number,
263
+ forget that we saw it. */
264
+ prefoffset=-1;
265
+ }
266
+ }
267
+ }
268
+ }
269
+
270
+ /* we're not interested in the page... just the serialno and granpos. */
271
+ if(prefoffset>=0)return(prefoffset);
272
+
273
+ *serialno = ret_serialno;
274
+ *granpos = ret_gran;
275
+ return(offset);
276
+
277
+ }
278
+
279
+ /* uses the local ogg_stream storage in vf; this is important for
280
+ non-streaming input sources */
281
+ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
282
+ long **serialno_list, int *serialno_n,
283
+ ogg_page *og_ptr){
284
+ ogg_page og;
285
+ ogg_packet op;
286
+ int i,ret;
287
+ int allbos=0;
288
+
289
+ if(!og_ptr){
290
+ ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
291
+ if(llret==OV_EREAD)return(OV_EREAD);
292
+ if(llret<0)return(OV_ENOTVORBIS);
293
+ og_ptr=&og;
294
+ }
295
+
296
+ vorbis_info_init(vi);
297
+ vorbis_comment_init(vc);
298
+ vf->ready_state=OPENED;
299
+
300
+ /* extract the serialnos of all BOS pages + the first set of vorbis
301
+ headers we see in the link */
302
+
303
+ while(ogg_page_bos(og_ptr)){
304
+ if(serialno_list){
305
+ if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){
306
+ /* a dupe serialnumber in an initial header packet set == invalid stream */
307
+ if(*serialno_list)_ogg_free(*serialno_list);
308
+ *serialno_list=0;
309
+ *serialno_n=0;
310
+ ret=OV_EBADHEADER;
311
+ goto bail_header;
312
+ }
313
+
314
+ _add_serialno(og_ptr,serialno_list,serialno_n);
315
+ }
316
+
317
+ if(vf->ready_state<STREAMSET){
318
+ /* we don't have a vorbis stream in this link yet, so begin
319
+ prospective stream setup. We need a stream to get packets */
320
+ ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
321
+ ogg_stream_pagein(&vf->os,og_ptr);
322
+
323
+ if(ogg_stream_packetout(&vf->os,&op) > 0 &&
324
+ vorbis_synthesis_idheader(&op)){
325
+ /* vorbis header; continue setup */
326
+ vf->ready_state=STREAMSET;
327
+ if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
328
+ ret=OV_EBADHEADER;
329
+ goto bail_header;
330
+ }
331
+ }
332
+ }
333
+
334
+ /* get next page */
335
+ {
336
+ ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
337
+ if(llret==OV_EREAD){
338
+ ret=OV_EREAD;
339
+ goto bail_header;
340
+ }
341
+ if(llret<0){
342
+ ret=OV_ENOTVORBIS;
343
+ goto bail_header;
344
+ }
345
+
346
+ /* if this page also belongs to our vorbis stream, submit it and break */
347
+ if(vf->ready_state==STREAMSET &&
348
+ vf->os.serialno == ogg_page_serialno(og_ptr)){
349
+ ogg_stream_pagein(&vf->os,og_ptr);
350
+ break;
351
+ }
352
+ }
353
+ }
354
+
355
+ if(vf->ready_state!=STREAMSET){
356
+ ret = OV_ENOTVORBIS;
357
+ goto bail_header;
358
+ }
359
+
360
+ while(1){
361
+
362
+ i=0;
363
+ while(i<2){ /* get a page loop */
364
+
365
+ while(i<2){ /* get a packet loop */
366
+
367
+ int result=ogg_stream_packetout(&vf->os,&op);
368
+ if(result==0)break;
369
+ if(result==-1){
370
+ ret=OV_EBADHEADER;
371
+ goto bail_header;
372
+ }
373
+
374
+ if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
375
+ goto bail_header;
376
+
377
+ i++;
378
+ }
379
+
380
+ while(i<2){
381
+ if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
382
+ ret=OV_EBADHEADER;
383
+ goto bail_header;
384
+ }
385
+
386
+ /* if this page belongs to the correct stream, go parse it */
387
+ if(vf->os.serialno == ogg_page_serialno(og_ptr)){
388
+ ogg_stream_pagein(&vf->os,og_ptr);
389
+ break;
390
+ }
391
+
392
+ /* if we never see the final vorbis headers before the link
393
+ ends, abort */
394
+ if(ogg_page_bos(og_ptr)){
395
+ if(allbos){
396
+ ret = OV_EBADHEADER;
397
+ goto bail_header;
398
+ }else
399
+ allbos=1;
400
+ }
401
+
402
+ /* otherwise, keep looking */
403
+ }
404
+ }
405
+
406
+ return 0;
407
+ }
408
+
409
+ bail_header:
410
+ vorbis_info_clear(vi);
411
+ vorbis_comment_clear(vc);
412
+ vf->ready_state=OPENED;
413
+
414
+ return ret;
415
+ }
416
+
417
+ /* Starting from current cursor position, get initial PCM offset of
418
+ next page. Consumes the page in the process without decoding
419
+ audio, however this is only called during stream parsing upon
420
+ seekable open. */
421
+ static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){
422
+ ogg_page og;
423
+ ogg_int64_t accumulated=0;
424
+ long lastblock=-1;
425
+ int result;
426
+ int serialno = vf->os.serialno;
427
+
428
+ while(1){
429
+ ogg_packet op;
430
+ if(_get_next_page(vf,&og,-1)<0)
431
+ break; /* should not be possible unless the file is truncated/mangled */
432
+
433
+ if(ogg_page_bos(&og)) break;
434
+ if(ogg_page_serialno(&og)!=serialno) continue;
435
+
436
+ /* count blocksizes of all frames in the page */
437
+ ogg_stream_pagein(&vf->os,&og);
438
+ while((result=ogg_stream_packetout(&vf->os,&op))){
439
+ if(result>0){ /* ignore holes */
440
+ long thisblock=vorbis_packet_blocksize(vi,&op);
441
+ if(lastblock!=-1)
442
+ accumulated+=(lastblock+thisblock)>>2;
443
+ lastblock=thisblock;
444
+ }
445
+ }
446
+
447
+ if(ogg_page_granulepos(&og)!=-1){
448
+ /* pcm offset of last packet on the first audio page */
449
+ accumulated= ogg_page_granulepos(&og)-accumulated;
450
+ break;
451
+ }
452
+ }
453
+
454
+ /* less than zero? Either a corrupt file or a stream with samples
455
+ trimmed off the beginning, a normal occurrence; in both cases set
456
+ the offset to zero */
457
+ if(accumulated<0)accumulated=0;
458
+
459
+ return accumulated;
460
+ }
461
+
462
+ /* finds each bitstream link one at a time using a bisection search
463
+ (has to begin by knowing the offset of the lb's initial page).
464
+ Recurses for each link so it can alloc the link storage after
465
+ finding them all, then unroll and fill the cache at the same time */
466
+ static int _bisect_forward_serialno(OggVorbis_File *vf,
467
+ ogg_int64_t begin,
468
+ ogg_int64_t searched,
469
+ ogg_int64_t end,
470
+ ogg_int64_t endgran,
471
+ int endserial,
472
+ long *currentno_list,
473
+ int currentnos,
474
+ long m){
475
+ ogg_int64_t pcmoffset;
476
+ ogg_int64_t dataoffset=searched;
477
+ ogg_int64_t endsearched=end;
478
+ ogg_int64_t next=end;
479
+ ogg_int64_t searchgran=-1;
480
+ ogg_page og;
481
+ ogg_int64_t ret,last;
482
+ int serialno = vf->os.serialno;
483
+
484
+ /* invariants:
485
+ we have the headers and serialnos for the link beginning at 'begin'
486
+ we have the offset and granpos of the last page in the file (potentially
487
+ not a page we care about)
488
+ */
489
+
490
+ /* Is the last page in our list of current serialnumbers? */
491
+ if(_lookup_serialno(endserial,currentno_list,currentnos)){
492
+
493
+ /* last page is in the starting serialno list, so we've bisected
494
+ down to (or just started with) a single link. Now we need to
495
+ find the last vorbis page belonging to the first vorbis stream
496
+ for this link. */
497
+
498
+ while(endserial != serialno){
499
+ endserial = serialno;
500
+ vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&endserial,&endgran);
501
+ }
502
+
503
+ vf->links=m+1;
504
+ if(vf->offsets)_ogg_free(vf->offsets);
505
+ if(vf->serialnos)_ogg_free(vf->serialnos);
506
+ if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
507
+
508
+ vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
509
+ vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
510
+ vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
511
+ vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
512
+ vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
513
+ vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
514
+
515
+ vf->offsets[m+1]=end;
516
+ vf->offsets[m]=begin;
517
+ vf->pcmlengths[m*2+1]=(endgran<0?0:endgran);
518
+
519
+ }else{
520
+
521
+ long *next_serialno_list=NULL;
522
+ int next_serialnos=0;
523
+ vorbis_info vi;
524
+ vorbis_comment vc;
525
+
526
+ /* the below guards against garbage seperating the last and
527
+ first pages of two links. */
528
+ while(searched<endsearched){
529
+ ogg_int64_t bisect;
530
+
531
+ if(endsearched-searched<CHUNKSIZE){
532
+ bisect=searched;
533
+ }else{
534
+ bisect=(searched+endsearched)/2;
535
+ }
536
+
537
+ if(bisect != vf->offset){
538
+ ret=_seek_helper(vf,bisect);
539
+ if(ret)return(ret);
540
+ }
541
+
542
+ last=_get_next_page(vf,&og,-1);
543
+ if(last==OV_EREAD)return(OV_EREAD);
544
+ if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){
545
+ endsearched=bisect;
546
+ if(last>=0)next=last;
547
+ }else{
548
+ searched=vf->offset;
549
+ }
550
+ }
551
+
552
+ /* Bisection point found */
553
+
554
+ /* for the time being, fetch end PCM offset the simple way */
555
+ {
556
+ int testserial = serialno+1;
557
+ vf->offset = next;
558
+ while(testserial != serialno){
559
+ testserial = serialno;
560
+ vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&testserial,&searchgran);
561
+ }
562
+ }
563
+
564
+ if(vf->offset!=next){
565
+ ret=_seek_helper(vf,next);
566
+ if(ret)return(ret);
567
+ }
568
+
569
+ ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL);
570
+ if(ret)return(ret);
571
+ serialno = vf->os.serialno;
572
+ dataoffset = vf->offset;
573
+
574
+ /* this will consume a page, however the next bistection always
575
+ starts with a raw seek */
576
+ pcmoffset = _initial_pcmoffset(vf,&vi);
577
+
578
+ ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial,
579
+ next_serialno_list,next_serialnos,m+1);
580
+ if(ret)return(ret);
581
+
582
+ if(next_serialno_list)_ogg_free(next_serialno_list);
583
+
584
+ vf->offsets[m+1]=next;
585
+ vf->serialnos[m+1]=serialno;
586
+ vf->dataoffsets[m+1]=dataoffset;
587
+
588
+ vf->vi[m+1]=vi;
589
+ vf->vc[m+1]=vc;
590
+
591
+ vf->pcmlengths[m*2+1]=searchgran;
592
+ vf->pcmlengths[m*2+2]=pcmoffset;
593
+ vf->pcmlengths[m*2+3]-=pcmoffset;
594
+ if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0;
595
+ }
596
+ return(0);
597
+ }
598
+
599
+ static int _make_decode_ready(OggVorbis_File *vf){
600
+ if(vf->ready_state>STREAMSET)return 0;
601
+ if(vf->ready_state<STREAMSET)return OV_EFAULT;
602
+ if(vf->seekable){
603
+ if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
604
+ return OV_EBADLINK;
605
+ }else{
606
+ if(vorbis_synthesis_init(&vf->vd,vf->vi))
607
+ return OV_EBADLINK;
608
+ }
609
+ vorbis_block_init(&vf->vd,&vf->vb);
610
+ vf->ready_state=INITSET;
611
+ vf->bittrack=0.f;
612
+ vf->samptrack=0.f;
613
+ return 0;
614
+ }
615
+
616
+ static int _open_seekable2(OggVorbis_File *vf){
617
+ ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1;
618
+ int endserial=vf->os.serialno;
619
+ int serialno=vf->os.serialno;
620
+
621
+ /* we're partially open and have a first link header state in
622
+ storage in vf */
623
+
624
+ /* fetch initial PCM offset */
625
+ ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi);
626
+
627
+ /* we can seek, so set out learning all about this file */
628
+ if(vf->callbacks.seek_func && vf->callbacks.tell_func){
629
+ (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
630
+ vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
631
+ }else{
632
+ vf->offset=vf->end=-1;
633
+ }
634
+
635
+ /* If seek_func is implemented, tell_func must also be implemented */
636
+ if(vf->end==-1) return(OV_EINVAL);
637
+
638
+ /* Get the offset of the last page of the physical bitstream, or, if
639
+ we're lucky the last vorbis page of this link as most OggVorbis
640
+ files will contain a single logical bitstream */
641
+ end=_get_prev_page_serial(vf,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran);
642
+ if(end<0)return(end);
643
+
644
+ /* now determine bitstream structure recursively */
645
+ if(_bisect_forward_serialno(vf,0,dataoffset,vf->offset,endgran,endserial,
646
+ vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);
647
+
648
+ vf->offsets[0]=0;
649
+ vf->serialnos[0]=serialno;
650
+ vf->dataoffsets[0]=dataoffset;
651
+ vf->pcmlengths[0]=pcmoffset;
652
+ vf->pcmlengths[1]-=pcmoffset;
653
+ if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0;
654
+
655
+ return(ov_raw_seek(vf,dataoffset));
656
+ }
657
+
658
+ /* clear out the current logical bitstream decoder */
659
+ static void _decode_clear(OggVorbis_File *vf){
660
+ vorbis_dsp_clear(&vf->vd);
661
+ vorbis_block_clear(&vf->vb);
662
+ vf->ready_state=OPENED;
663
+ }
664
+
665
+ /* fetch and process a packet. Handles the case where we're at a
666
+ bitstream boundary and dumps the decoding machine. If the decoding
667
+ machine is unloaded, it loads it. It also keeps pcm_offset up to
668
+ date (seek and read both use this. seek uses a special hack with
669
+ readp).
670
+
671
+ return: <0) error, OV_HOLE (lost packet) or OV_EOF
672
+ 0) need more data (only if readp==0)
673
+ 1) got a packet
674
+ */
675
+
676
+ static int _fetch_and_process_packet(OggVorbis_File *vf,
677
+ ogg_packet *op_in,
678
+ int readp,
679
+ int spanp){
680
+ ogg_page og;
681
+
682
+ /* handle one packet. Try to fetch it from current stream state */
683
+ /* extract packets from page */
684
+ while(1){
685
+
686
+ if(vf->ready_state==STREAMSET){
687
+ int ret=_make_decode_ready(vf);
688
+ if(ret<0)return ret;
689
+ }
690
+
691
+ /* process a packet if we can. */
692
+
693
+ if(vf->ready_state==INITSET){
694
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
695
+
696
+ while(1) {
697
+ ogg_packet op;
698
+ ogg_packet *op_ptr=(op_in?op_in:&op);
699
+ int result=ogg_stream_packetout(&vf->os,op_ptr);
700
+ ogg_int64_t granulepos;
701
+
702
+ op_in=NULL;
703
+ if(result==-1)return(OV_HOLE); /* hole in the data. */
704
+ if(result>0){
705
+ /* got a packet. process it */
706
+ granulepos=op_ptr->granulepos;
707
+ if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
708
+ header handling. The
709
+ header packets aren't
710
+ audio, so if/when we
711
+ submit them,
712
+ vorbis_synthesis will
713
+ reject them */
714
+
715
+ /* suck in the synthesis data and track bitrate */
716
+ {
717
+ int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
718
+ /* for proper use of libvorbis within libvorbisfile,
719
+ oldsamples will always be zero. */
720
+ if(oldsamples)return(OV_EFAULT);
721
+
722
+ vorbis_synthesis_blockin(&vf->vd,&vf->vb);
723
+ vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
724
+ vf->bittrack+=op_ptr->bytes*8;
725
+ }
726
+
727
+ /* update the pcm offset. */
728
+ if(granulepos!=-1 && !op_ptr->e_o_s){
729
+ int link=(vf->seekable?vf->current_link:0);
730
+ int i,samples;
731
+
732
+ /* this packet has a pcm_offset on it (the last packet
733
+ completed on a page carries the offset) After processing
734
+ (above), we know the pcm position of the *last* sample
735
+ ready to be returned. Find the offset of the *first*
736
+
737
+ As an aside, this trick is inaccurate if we begin
738
+ reading anew right at the last page; the end-of-stream
739
+ granulepos declares the last frame in the stream, and the
740
+ last packet of the last page may be a partial frame.
741
+ So, we need a previous granulepos from an in-sequence page
742
+ to have a reference point. Thus the !op_ptr->e_o_s clause
743
+ above */
744
+
745
+ if(vf->seekable && link>0)
746
+ granulepos-=vf->pcmlengths[link*2];
747
+ if(granulepos<0)granulepos=0; /* actually, this
748
+ shouldn't be possible
749
+ here unless the stream
750
+ is very broken */
751
+
752
+ samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
753
+
754
+ granulepos-=samples;
755
+ for(i=0;i<link;i++)
756
+ granulepos+=vf->pcmlengths[i*2+1];
757
+ vf->pcm_offset=granulepos;
758
+ }
759
+ return(1);
760
+ }
761
+ }
762
+ else
763
+ break;
764
+ }
765
+ }
766
+
767
+ if(vf->ready_state>=OPENED){
768
+ ogg_int64_t ret;
769
+
770
+ while(1){
771
+ /* the loop is not strictly necessary, but there's no sense in
772
+ doing the extra checks of the larger loop for the common
773
+ case in a multiplexed bistream where the page is simply
774
+ part of a different logical bitstream; keep reading until
775
+ we get one with the correct serialno */
776
+
777
+ if(!readp)return(0);
778
+ if((ret=_get_next_page(vf,&og,-1))<0){
779
+ return(OV_EOF); /* eof. leave unitialized */
780
+ }
781
+
782
+ /* bitrate tracking; add the header's bytes here, the body bytes
783
+ are done by packet above */
784
+ vf->bittrack+=og.header_len*8;
785
+
786
+ if(vf->ready_state==INITSET){
787
+ if(vf->current_serialno!=ogg_page_serialno(&og)){
788
+
789
+ /* two possibilities:
790
+ 1) our decoding just traversed a bitstream boundary
791
+ 2) another stream is multiplexed into this logical section */
792
+
793
+ if(ogg_page_bos(&og)){
794
+ /* boundary case */
795
+ if(!spanp)
796
+ return(OV_EOF);
797
+
798
+ _decode_clear(vf);
799
+
800
+ if(!vf->seekable){
801
+ vorbis_info_clear(vf->vi);
802
+ vorbis_comment_clear(vf->vc);
803
+ }
804
+ break;
805
+
806
+ }else
807
+ continue; /* possibility #2 */
808
+ }
809
+ }
810
+
811
+ break;
812
+ }
813
+ }
814
+
815
+ /* Do we need to load a new machine before submitting the page? */
816
+ /* This is different in the seekable and non-seekable cases.
817
+
818
+ In the seekable case, we already have all the header
819
+ information loaded and cached; we just initialize the machine
820
+ with it and continue on our merry way.
821
+
822
+ In the non-seekable (streaming) case, we'll only be at a
823
+ boundary if we just left the previous logical bitstream and
824
+ we're now nominally at the header of the next bitstream
825
+ */
826
+
827
+ if(vf->ready_state!=INITSET){
828
+ int link;
829
+
830
+ if(vf->ready_state<STREAMSET){
831
+ if(vf->seekable){
832
+ long serialno = ogg_page_serialno(&og);
833
+
834
+ /* match the serialno to bitstream section. We use this rather than
835
+ offset positions to avoid problems near logical bitstream
836
+ boundaries */
837
+
838
+ for(link=0;link<vf->links;link++)
839
+ if(vf->serialnos[link]==serialno)break;
840
+
841
+ if(link==vf->links) continue; /* not the desired Vorbis
842
+ bitstream section; keep
843
+ trying */
844
+
845
+ vf->current_serialno=serialno;
846
+ vf->current_link=link;
847
+
848
+ ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
849
+ vf->ready_state=STREAMSET;
850
+
851
+ }else{
852
+ /* we're streaming */
853
+ /* fetch the three header packets, build the info struct */
854
+
855
+ int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og);
856
+ if(ret)return(ret);
857
+ vf->current_serialno=vf->os.serialno;
858
+ vf->current_link++;
859
+ link=0;
860
+ }
861
+ }
862
+ }
863
+
864
+ /* the buffered page is the data we want, and we're ready for it;
865
+ add it to the stream state */
866
+ ogg_stream_pagein(&vf->os,&og);
867
+
868
+ }
869
+ }
870
+
871
+ /* if, eg, 64 bit stdio is configured by default, this will build with
872
+ fseek64 */
873
+ static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
874
+ if(f==NULL)return(-1);
875
+ return fseek(f,off,whence);
876
+ }
877
+
878
+ static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
879
+ long ibytes, ov_callbacks callbacks){
880
+ int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
881
+ long *serialno_list=NULL;
882
+ int serialno_list_size=0;
883
+ int ret;
884
+
885
+ memset(vf,0,sizeof(*vf));
886
+ vf->datasource=f;
887
+ vf->callbacks = callbacks;
888
+
889
+ /* init the framing state */
890
+ ogg_sync_init(&vf->oy);
891
+
892
+ /* perhaps some data was previously read into a buffer for testing
893
+ against other stream types. Allow initialization from this
894
+ previously read data (especially as we may be reading from a
895
+ non-seekable stream) */
896
+ if(initial){
897
+ char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
898
+ memcpy(buffer,initial,ibytes);
899
+ ogg_sync_wrote(&vf->oy,ibytes);
900
+ }
901
+
902
+ /* can we seek? Stevens suggests the seek test was portable */
903
+ if(offsettest!=-1)vf->seekable=1;
904
+
905
+ /* No seeking yet; Set up a 'single' (current) logical bitstream
906
+ entry for partial open */
907
+ vf->links=1;
908
+ vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
909
+ vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
910
+ ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
911
+
912
+ /* Fetch all BOS pages, store the vorbis header and all seen serial
913
+ numbers, load subsequent vorbis setup headers */
914
+ if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){
915
+ vf->datasource=NULL;
916
+ ov_clear(vf);
917
+ }else{
918
+ /* serial number list for first link needs to be held somewhere
919
+ for second stage of seekable stream open; this saves having to
920
+ seek/reread first link's serialnumber data then. */
921
+ vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
922
+ vf->serialnos[0]=vf->current_serialno=vf->os.serialno;
923
+ vf->serialnos[1]=serialno_list_size;
924
+ memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
925
+
926
+ vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets));
927
+ vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets));
928
+ vf->offsets[0]=0;
929
+ vf->dataoffsets[0]=vf->offset;
930
+
931
+ vf->ready_state=PARTOPEN;
932
+ }
933
+ if(serialno_list)_ogg_free(serialno_list);
934
+ return(ret);
935
+ }
936
+
937
+ static int _ov_open2(OggVorbis_File *vf){
938
+ if(vf->ready_state != PARTOPEN) return OV_EINVAL;
939
+ vf->ready_state=OPENED;
940
+ if(vf->seekable){
941
+ int ret=_open_seekable2(vf);
942
+ if(ret){
943
+ vf->datasource=NULL;
944
+ ov_clear(vf);
945
+ }
946
+ return(ret);
947
+ }else
948
+ vf->ready_state=STREAMSET;
949
+
950
+ return 0;
951
+ }
952
+
953
+
954
+ /* clear out the OggVorbis_File struct */
955
+ int ov_clear(OggVorbis_File *vf){
956
+ if(vf){
957
+ vorbis_block_clear(&vf->vb);
958
+ vorbis_dsp_clear(&vf->vd);
959
+ ogg_stream_clear(&vf->os);
960
+
961
+ if(vf->vi && vf->links){
962
+ int i;
963
+ for(i=0;i<vf->links;i++){
964
+ vorbis_info_clear(vf->vi+i);
965
+ vorbis_comment_clear(vf->vc+i);
966
+ }
967
+ _ogg_free(vf->vi);
968
+ _ogg_free(vf->vc);
969
+ }
970
+ if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
971
+ if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
972
+ if(vf->serialnos)_ogg_free(vf->serialnos);
973
+ if(vf->offsets)_ogg_free(vf->offsets);
974
+ ogg_sync_clear(&vf->oy);
975
+ if(vf->datasource && vf->callbacks.close_func)
976
+ (vf->callbacks.close_func)(vf->datasource);
977
+ memset(vf,0,sizeof(*vf));
978
+ }
979
+ #ifdef DEBUG_LEAKS
980
+ _VDBG_dump();
981
+ #endif
982
+ return(0);
983
+ }
984
+
985
+ /* inspects the OggVorbis file and finds/documents all the logical
986
+ bitstreams contained in it. Tries to be tolerant of logical
987
+ bitstream sections that are truncated/woogie.
988
+
989
+ return: -1) error
990
+ 0) OK
991
+ */
992
+
993
+ int ov_open_callbacks(void *f,OggVorbis_File *vf,
994
+ const char *initial,long ibytes,ov_callbacks callbacks){
995
+ int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
996
+ if(ret)return ret;
997
+ return _ov_open2(vf);
998
+ }
999
+
1000
+ int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
1001
+ ov_callbacks callbacks = {
1002
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
1003
+ (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
1004
+ (int (*)(void *)) fclose,
1005
+ (long (*)(void *)) ftell
1006
+ };
1007
+
1008
+ return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
1009
+ }
1010
+
1011
+ int ov_fopen(const char *path,OggVorbis_File *vf){
1012
+ int ret;
1013
+ FILE *f = fopen(path,"rb");
1014
+ if(!f) return -1;
1015
+
1016
+ ret = ov_open(f,vf,NULL,0);
1017
+ if(ret) fclose(f);
1018
+ return ret;
1019
+ }
1020
+
1021
+
1022
+ /* cheap hack for game usage where downsampling is desirable; there's
1023
+ no need for SRC as we can just do it cheaply in libvorbis. */
1024
+
1025
+ int ov_halfrate(OggVorbis_File *vf,int flag){
1026
+ int i;
1027
+ if(vf->vi==NULL)return OV_EINVAL;
1028
+ if(vf->ready_state>STREAMSET){
1029
+ /* clear out stream state; dumping the decode machine is needed to
1030
+ reinit the MDCT lookups. */
1031
+ vorbis_dsp_clear(&vf->vd);
1032
+ vorbis_block_clear(&vf->vb);
1033
+ vf->ready_state=STREAMSET;
1034
+ if(vf->pcm_offset>=0){
1035
+ ogg_int64_t pos=vf->pcm_offset;
1036
+ vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */
1037
+ ov_pcm_seek(vf,pos);
1038
+ }
1039
+ }
1040
+
1041
+ for(i=0;i<vf->links;i++){
1042
+ if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
1043
+ if(flag) ov_halfrate(vf,0);
1044
+ return OV_EINVAL;
1045
+ }
1046
+ }
1047
+ return 0;
1048
+ }
1049
+
1050
+ int ov_halfrate_p(OggVorbis_File *vf){
1051
+ if(vf->vi==NULL)return OV_EINVAL;
1052
+ return vorbis_synthesis_halfrate_p(vf->vi);
1053
+ }
1054
+
1055
+ /* Only partially open the vorbis file; test for Vorbisness, and load
1056
+ the headers for the first chain. Do not seek (although test for
1057
+ seekability). Use ov_test_open to finish opening the file, else
1058
+ ov_clear to close/free it. Same return codes as open. */
1059
+
1060
+ int ov_test_callbacks(void *f,OggVorbis_File *vf,
1061
+ const char *initial,long ibytes,ov_callbacks callbacks)
1062
+ {
1063
+ return _ov_open1(f,vf,initial,ibytes,callbacks);
1064
+ }
1065
+
1066
+ int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
1067
+ ov_callbacks callbacks = {
1068
+ (size_t (*)(void *, size_t, size_t, void *)) fread,
1069
+ (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
1070
+ (int (*)(void *)) fclose,
1071
+ (long (*)(void *)) ftell
1072
+ };
1073
+
1074
+ return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
1075
+ }
1076
+
1077
+ int ov_test_open(OggVorbis_File *vf){
1078
+ if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
1079
+ return _ov_open2(vf);
1080
+ }
1081
+
1082
+ /* How many logical bitstreams in this physical bitstream? */
1083
+ long ov_streams(OggVorbis_File *vf){
1084
+ return vf->links;
1085
+ }
1086
+
1087
+ /* Is the FILE * associated with vf seekable? */
1088
+ long ov_seekable(OggVorbis_File *vf){
1089
+ return vf->seekable;
1090
+ }
1091
+
1092
+ /* returns the bitrate for a given logical bitstream or the entire
1093
+ physical bitstream. If the file is open for random access, it will
1094
+ find the *actual* average bitrate. If the file is streaming, it
1095
+ returns the nominal bitrate (if set) else the average of the
1096
+ upper/lower bounds (if set) else -1 (unset).
1097
+
1098
+ If you want the actual bitrate field settings, get them from the
1099
+ vorbis_info structs */
1100
+
1101
+ long ov_bitrate(OggVorbis_File *vf,int i){
1102
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1103
+ if(i>=vf->links)return(OV_EINVAL);
1104
+ if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
1105
+ if(i<0){
1106
+ ogg_int64_t bits=0;
1107
+ int i;
1108
+ float br;
1109
+ for(i=0;i<vf->links;i++)
1110
+ bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
1111
+ /* This once read: return(rint(bits/ov_time_total(vf,-1)));
1112
+ * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
1113
+ * so this is slightly transformed to make it work.
1114
+ */
1115
+ br = bits/ov_time_total(vf,-1);
1116
+ return(rint(br));
1117
+ }else{
1118
+ if(vf->seekable){
1119
+ /* return the actual bitrate */
1120
+ return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
1121
+ }else{
1122
+ /* return nominal if set */
1123
+ if(vf->vi[i].bitrate_nominal>0){
1124
+ return vf->vi[i].bitrate_nominal;
1125
+ }else{
1126
+ if(vf->vi[i].bitrate_upper>0){
1127
+ if(vf->vi[i].bitrate_lower>0){
1128
+ return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
1129
+ }else{
1130
+ return vf->vi[i].bitrate_upper;
1131
+ }
1132
+ }
1133
+ return(OV_FALSE);
1134
+ }
1135
+ }
1136
+ }
1137
+ }
1138
+
1139
+ /* returns the actual bitrate since last call. returns -1 if no
1140
+ additional data to offer since last call (or at beginning of stream),
1141
+ EINVAL if stream is only partially open
1142
+ */
1143
+ long ov_bitrate_instant(OggVorbis_File *vf){
1144
+ int link=(vf->seekable?vf->current_link:0);
1145
+ long ret;
1146
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1147
+ if(vf->samptrack==0)return(OV_FALSE);
1148
+ ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
1149
+ vf->bittrack=0.f;
1150
+ vf->samptrack=0.f;
1151
+ return(ret);
1152
+ }
1153
+
1154
+ /* Guess */
1155
+ long ov_serialnumber(OggVorbis_File *vf,int i){
1156
+ if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
1157
+ if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
1158
+ if(i<0){
1159
+ return(vf->current_serialno);
1160
+ }else{
1161
+ return(vf->serialnos[i]);
1162
+ }
1163
+ }
1164
+
1165
+ /* returns: total raw (compressed) length of content if i==-1
1166
+ raw (compressed) length of that logical bitstream for i==0 to n
1167
+ OV_EINVAL if the stream is not seekable (we can't know the length)
1168
+ or if stream is only partially open
1169
+ */
1170
+ ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
1171
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1172
+ if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1173
+ if(i<0){
1174
+ ogg_int64_t acc=0;
1175
+ int i;
1176
+ for(i=0;i<vf->links;i++)
1177
+ acc+=ov_raw_total(vf,i);
1178
+ return(acc);
1179
+ }else{
1180
+ return(vf->offsets[i+1]-vf->offsets[i]);
1181
+ }
1182
+ }
1183
+
1184
+ /* returns: total PCM length (samples) of content if i==-1 PCM length
1185
+ (samples) of that logical bitstream for i==0 to n
1186
+ OV_EINVAL if the stream is not seekable (we can't know the
1187
+ length) or only partially open
1188
+ */
1189
+ ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
1190
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1191
+ if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1192
+ if(i<0){
1193
+ ogg_int64_t acc=0;
1194
+ int i;
1195
+ for(i=0;i<vf->links;i++)
1196
+ acc+=ov_pcm_total(vf,i);
1197
+ return(acc);
1198
+ }else{
1199
+ return(vf->pcmlengths[i*2+1]);
1200
+ }
1201
+ }
1202
+
1203
+ /* returns: total seconds of content if i==-1
1204
+ seconds in that logical bitstream for i==0 to n
1205
+ OV_EINVAL if the stream is not seekable (we can't know the
1206
+ length) or only partially open
1207
+ */
1208
+ double ov_time_total(OggVorbis_File *vf,int i){
1209
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1210
+ if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1211
+ if(i<0){
1212
+ double acc=0;
1213
+ int i;
1214
+ for(i=0;i<vf->links;i++)
1215
+ acc+=ov_time_total(vf,i);
1216
+ return(acc);
1217
+ }else{
1218
+ return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate);
1219
+ }
1220
+ }
1221
+
1222
+ /* seek to an offset relative to the *compressed* data. This also
1223
+ scans packets to update the PCM cursor. It will cross a logical
1224
+ bitstream boundary, but only if it can't get any packets out of the
1225
+ tail of the bitstream we seek to (so no surprises).
1226
+
1227
+ returns zero on success, nonzero on failure */
1228
+
1229
+ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
1230
+ ogg_stream_state work_os;
1231
+ int ret;
1232
+
1233
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1234
+ if(!vf->seekable)
1235
+ return(OV_ENOSEEK); /* don't dump machine if we can't seek */
1236
+
1237
+ if(pos<0 || pos>vf->end)return(OV_EINVAL);
1238
+
1239
+ /* is the seek position outside our current link [if any]? */
1240
+ if(vf->ready_state>=STREAMSET){
1241
+ if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1])
1242
+ _decode_clear(vf); /* clear out stream state */
1243
+ }
1244
+
1245
+ /* don't yet clear out decoding machine (if it's initialized), in
1246
+ the case we're in the same link. Restart the decode lapping, and
1247
+ let _fetch_and_process_packet deal with a potential bitstream
1248
+ boundary */
1249
+ vf->pcm_offset=-1;
1250
+ ogg_stream_reset_serialno(&vf->os,
1251
+ vf->current_serialno); /* must set serialno */
1252
+ vorbis_synthesis_restart(&vf->vd);
1253
+
1254
+ ret=_seek_helper(vf,pos);
1255
+ if(ret)goto seek_error;
1256
+
1257
+ /* we need to make sure the pcm_offset is set, but we don't want to
1258
+ advance the raw cursor past good packets just to get to the first
1259
+ with a granulepos. That's not equivalent behavior to beginning
1260
+ decoding as immediately after the seek position as possible.
1261
+
1262
+ So, a hack. We use two stream states; a local scratch state and
1263
+ the shared vf->os stream state. We use the local state to
1264
+ scan, and the shared state as a buffer for later decode.
1265
+
1266
+ Unfortuantely, on the last page we still advance to last packet
1267
+ because the granulepos on the last page is not necessarily on a
1268
+ packet boundary, and we need to make sure the granpos is
1269
+ correct.
1270
+ */
1271
+
1272
+ {
1273
+ ogg_page og;
1274
+ ogg_packet op;
1275
+ int lastblock=0;
1276
+ int accblock=0;
1277
+ int thisblock=0;
1278
+ int lastflag=0;
1279
+ int firstflag=0;
1280
+ ogg_int64_t pagepos=-1;
1281
+
1282
+ ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
1283
+ ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
1284
+ return from not necessarily
1285
+ starting from the beginning */
1286
+
1287
+ while(1){
1288
+ if(vf->ready_state>=STREAMSET){
1289
+ /* snarf/scan a packet if we can */
1290
+ int result=ogg_stream_packetout(&work_os,&op);
1291
+
1292
+ if(result>0){
1293
+
1294
+ if(vf->vi[vf->current_link].codec_setup){
1295
+ thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1296
+ if(thisblock<0){
1297
+ ogg_stream_packetout(&vf->os,NULL);
1298
+ thisblock=0;
1299
+ }else{
1300
+
1301
+ /* We can't get a guaranteed correct pcm position out of the
1302
+ last page in a stream because it might have a 'short'
1303
+ granpos, which can only be detected in the presence of a
1304
+ preceding page. However, if the last page is also the first
1305
+ page, the granpos rules of a first page take precedence. Not
1306
+ only that, but for first==last, the EOS page must be treated
1307
+ as if its a normal first page for the stream to open/play. */
1308
+ if(lastflag && !firstflag)
1309
+ ogg_stream_packetout(&vf->os,NULL);
1310
+ else
1311
+ if(lastblock)accblock+=(lastblock+thisblock)>>2;
1312
+ }
1313
+
1314
+ if(op.granulepos!=-1){
1315
+ int i,link=vf->current_link;
1316
+ ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
1317
+ if(granulepos<0)granulepos=0;
1318
+
1319
+ for(i=0;i<link;i++)
1320
+ granulepos+=vf->pcmlengths[i*2+1];
1321
+ vf->pcm_offset=granulepos-accblock;
1322
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
1323
+ break;
1324
+ }
1325
+ lastblock=thisblock;
1326
+ continue;
1327
+ }else
1328
+ ogg_stream_packetout(&vf->os,NULL);
1329
+ }
1330
+ }
1331
+
1332
+ if(!lastblock){
1333
+ pagepos=_get_next_page(vf,&og,-1);
1334
+ if(pagepos<0){
1335
+ vf->pcm_offset=ov_pcm_total(vf,-1);
1336
+ break;
1337
+ }
1338
+ }else{
1339
+ /* huh? Bogus stream with packets but no granulepos */
1340
+ vf->pcm_offset=-1;
1341
+ break;
1342
+ }
1343
+
1344
+ /* has our decoding just traversed a bitstream boundary? */
1345
+ if(vf->ready_state>=STREAMSET){
1346
+ if(vf->current_serialno!=ogg_page_serialno(&og)){
1347
+
1348
+ /* two possibilities:
1349
+ 1) our decoding just traversed a bitstream boundary
1350
+ 2) another stream is multiplexed into this logical section? */
1351
+
1352
+ if(ogg_page_bos(&og)){
1353
+ /* we traversed */
1354
+ _decode_clear(vf); /* clear out stream state */
1355
+ ogg_stream_clear(&work_os);
1356
+ } /* else, do nothing; next loop will scoop another page */
1357
+ }
1358
+ }
1359
+
1360
+ if(vf->ready_state<STREAMSET){
1361
+ int link;
1362
+ long serialno = ogg_page_serialno(&og);
1363
+
1364
+ for(link=0;link<vf->links;link++)
1365
+ if(vf->serialnos[link]==serialno)break;
1366
+
1367
+ if(link==vf->links) continue; /* not the desired Vorbis
1368
+ bitstream section; keep
1369
+ trying */
1370
+ vf->current_link=link;
1371
+ vf->current_serialno=serialno;
1372
+ ogg_stream_reset_serialno(&vf->os,serialno);
1373
+ ogg_stream_reset_serialno(&work_os,serialno);
1374
+ vf->ready_state=STREAMSET;
1375
+ firstflag=(pagepos<=vf->dataoffsets[link]);
1376
+ }
1377
+
1378
+ ogg_stream_pagein(&vf->os,&og);
1379
+ ogg_stream_pagein(&work_os,&og);
1380
+ lastflag=ogg_page_eos(&og);
1381
+
1382
+ }
1383
+ }
1384
+
1385
+ ogg_stream_clear(&work_os);
1386
+ vf->bittrack=0.f;
1387
+ vf->samptrack=0.f;
1388
+ return(0);
1389
+
1390
+ seek_error:
1391
+ /* dump the machine so we're in a known state */
1392
+ vf->pcm_offset=-1;
1393
+ ogg_stream_clear(&work_os);
1394
+ _decode_clear(vf);
1395
+ return OV_EBADLINK;
1396
+ }
1397
+
1398
+ /* Page granularity seek (faster than sample granularity because we
1399
+ don't do the last bit of decode to find a specific sample).
1400
+
1401
+ Seek to the last [granule marked] page preceding the specified pos
1402
+ location, such that decoding past the returned point will quickly
1403
+ arrive at the requested position. */
1404
+ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
1405
+ int link=-1;
1406
+ ogg_int64_t result=0;
1407
+ ogg_int64_t total=ov_pcm_total(vf,-1);
1408
+
1409
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1410
+ if(!vf->seekable)return(OV_ENOSEEK);
1411
+
1412
+ if(pos<0 || pos>total)return(OV_EINVAL);
1413
+
1414
+ /* which bitstream section does this pcm offset occur in? */
1415
+ for(link=vf->links-1;link>=0;link--){
1416
+ total-=vf->pcmlengths[link*2+1];
1417
+ if(pos>=total)break;
1418
+ }
1419
+
1420
+ /* search within the logical bitstream for the page with the highest
1421
+ pcm_pos preceding (or equal to) pos. There is a danger here;
1422
+ missing pages or incorrect frame number information in the
1423
+ bitstream could make our task impossible. Account for that (it
1424
+ would be an error condition) */
1425
+
1426
+ /* new search algorithm by HB (Nicholas Vinen) */
1427
+ {
1428
+ ogg_int64_t end=vf->offsets[link+1];
1429
+ ogg_int64_t begin=vf->offsets[link];
1430
+ ogg_int64_t begintime = vf->pcmlengths[link*2];
1431
+ ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
1432
+ ogg_int64_t target=pos-total+begintime;
1433
+ ogg_int64_t best=begin;
1434
+
1435
+ ogg_page og;
1436
+ while(begin<end){
1437
+ ogg_int64_t bisect;
1438
+
1439
+ if(end-begin<CHUNKSIZE){
1440
+ bisect=begin;
1441
+ }else{
1442
+ /* take a (pretty decent) guess. */
1443
+ bisect=begin +
1444
+ (ogg_int64_t)((double)(target-begintime)*(end-begin)/(endtime-begintime))
1445
+ - CHUNKSIZE;
1446
+ if(bisect<begin+CHUNKSIZE)
1447
+ bisect=begin;
1448
+ }
1449
+
1450
+ if(bisect!=vf->offset){
1451
+ result=_seek_helper(vf,bisect);
1452
+ if(result) goto seek_error;
1453
+ }
1454
+
1455
+ while(begin<end){
1456
+ result=_get_next_page(vf,&og,end-vf->offset);
1457
+ if(result==OV_EREAD) goto seek_error;
1458
+ if(result<0){
1459
+ if(bisect<=begin+1)
1460
+ end=begin; /* found it */
1461
+ else{
1462
+ if(bisect==0) goto seek_error;
1463
+ bisect-=CHUNKSIZE;
1464
+ if(bisect<=begin)bisect=begin+1;
1465
+ result=_seek_helper(vf,bisect);
1466
+ if(result) goto seek_error;
1467
+ }
1468
+ }else{
1469
+ ogg_int64_t granulepos;
1470
+
1471
+ if(ogg_page_serialno(&og)!=vf->serialnos[link])
1472
+ continue;
1473
+
1474
+ granulepos=ogg_page_granulepos(&og);
1475
+ if(granulepos==-1)continue;
1476
+
1477
+ if(granulepos<target){
1478
+ best=result; /* raw offset of packet with granulepos */
1479
+ begin=vf->offset; /* raw offset of next page */
1480
+ begintime=granulepos;
1481
+
1482
+ if(target-begintime>44100)break;
1483
+ bisect=begin; /* *not* begin + 1 */
1484
+ }else{
1485
+ if(bisect<=begin+1)
1486
+ end=begin; /* found it */
1487
+ else{
1488
+ if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
1489
+ end=result;
1490
+ bisect-=CHUNKSIZE; /* an endless loop otherwise. */
1491
+ if(bisect<=begin)bisect=begin+1;
1492
+ result=_seek_helper(vf,bisect);
1493
+ if(result) goto seek_error;
1494
+ }else{
1495
+ end=bisect;
1496
+ endtime=granulepos;
1497
+ break;
1498
+ }
1499
+ }
1500
+ }
1501
+ }
1502
+ }
1503
+ }
1504
+
1505
+ /* found our page. seek to it, update pcm offset. Easier case than
1506
+ raw_seek, don't keep packets preceding granulepos. */
1507
+ {
1508
+ ogg_page og;
1509
+ ogg_packet op;
1510
+
1511
+ /* seek */
1512
+ result=_seek_helper(vf,best);
1513
+ vf->pcm_offset=-1;
1514
+ if(result) goto seek_error;
1515
+ result=_get_next_page(vf,&og,-1);
1516
+ if(result<0) goto seek_error;
1517
+
1518
+ if(link!=vf->current_link){
1519
+ /* Different link; dump entire decode machine */
1520
+ _decode_clear(vf);
1521
+
1522
+ vf->current_link=link;
1523
+ vf->current_serialno=vf->serialnos[link];
1524
+ vf->ready_state=STREAMSET;
1525
+
1526
+ }else{
1527
+ vorbis_synthesis_restart(&vf->vd);
1528
+ }
1529
+
1530
+ ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1531
+ ogg_stream_pagein(&vf->os,&og);
1532
+
1533
+ /* pull out all but last packet; the one with granulepos */
1534
+ while(1){
1535
+ result=ogg_stream_packetpeek(&vf->os,&op);
1536
+ if(result==0){
1537
+ /* !!! the packet finishing this page originated on a
1538
+ preceding page. Keep fetching previous pages until we
1539
+ get one with a granulepos or without the 'continued' flag
1540
+ set. Then just use raw_seek for simplicity. */
1541
+
1542
+ result=_seek_helper(vf,best);
1543
+ if(result<0) goto seek_error;
1544
+
1545
+ while(1){
1546
+ result=_get_prev_page(vf,&og);
1547
+ if(result<0) goto seek_error;
1548
+ if(ogg_page_serialno(&og)==vf->current_serialno &&
1549
+ (ogg_page_granulepos(&og)>-1 ||
1550
+ !ogg_page_continued(&og))){
1551
+ return ov_raw_seek(vf,result);
1552
+ }
1553
+ vf->offset=result;
1554
+ }
1555
+ }
1556
+ if(result<0){
1557
+ result = OV_EBADPACKET;
1558
+ goto seek_error;
1559
+ }
1560
+ if(op.granulepos!=-1){
1561
+ vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1562
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
1563
+ vf->pcm_offset+=total;
1564
+ break;
1565
+ }else
1566
+ result=ogg_stream_packetout(&vf->os,NULL);
1567
+ }
1568
+ }
1569
+ }
1570
+
1571
+ /* verify result */
1572
+ if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1573
+ result=OV_EFAULT;
1574
+ goto seek_error;
1575
+ }
1576
+ vf->bittrack=0.f;
1577
+ vf->samptrack=0.f;
1578
+ return(0);
1579
+
1580
+ seek_error:
1581
+ /* dump machine so we're in a known state */
1582
+ vf->pcm_offset=-1;
1583
+ _decode_clear(vf);
1584
+ return (int)result;
1585
+ }
1586
+
1587
+ /* seek to a sample offset relative to the decompressed pcm stream
1588
+ returns zero on success, nonzero on failure */
1589
+
1590
+ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1591
+ int thisblock,lastblock=0;
1592
+ int ret=ov_pcm_seek_page(vf,pos);
1593
+ if(ret<0)return(ret);
1594
+ if((ret=_make_decode_ready(vf)))return ret;
1595
+
1596
+ /* discard leading packets we don't need for the lapping of the
1597
+ position we want; don't decode them */
1598
+
1599
+ while(1){
1600
+ ogg_packet op;
1601
+ ogg_page og;
1602
+
1603
+ int ret=ogg_stream_packetpeek(&vf->os,&op);
1604
+ if(ret>0){
1605
+ thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1606
+ if(thisblock<0){
1607
+ ogg_stream_packetout(&vf->os,NULL);
1608
+ continue; /* non audio packet */
1609
+ }
1610
+ if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1611
+
1612
+ if(vf->pcm_offset+((thisblock+
1613
+ vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1614
+
1615
+ /* remove the packet from packet queue and track its granulepos */
1616
+ ogg_stream_packetout(&vf->os,NULL);
1617
+ vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with
1618
+ only tracking, no
1619
+ pcm_decode */
1620
+ vorbis_synthesis_blockin(&vf->vd,&vf->vb);
1621
+
1622
+ /* end of logical stream case is hard, especially with exact
1623
+ length positioning. */
1624
+
1625
+ if(op.granulepos>-1){
1626
+ int i;
1627
+ /* always believe the stream markers */
1628
+ vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1629
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
1630
+ for(i=0;i<vf->current_link;i++)
1631
+ vf->pcm_offset+=vf->pcmlengths[i*2+1];
1632
+ }
1633
+
1634
+ lastblock=thisblock;
1635
+
1636
+ }else{
1637
+ if(ret<0 && ret!=OV_HOLE)break;
1638
+
1639
+ /* suck in a new page */
1640
+ if(_get_next_page(vf,&og,-1)<0)break;
1641
+ if(ogg_page_bos(&og))_decode_clear(vf);
1642
+
1643
+ if(vf->ready_state<STREAMSET){
1644
+ long serialno=ogg_page_serialno(&og);
1645
+ int link;
1646
+
1647
+ for(link=0;link<vf->links;link++)
1648
+ if(vf->serialnos[link]==serialno)break;
1649
+ if(link==vf->links) continue;
1650
+ vf->current_link=link;
1651
+
1652
+ vf->ready_state=STREAMSET;
1653
+ vf->current_serialno=ogg_page_serialno(&og);
1654
+ ogg_stream_reset_serialno(&vf->os,serialno);
1655
+ ret=_make_decode_ready(vf);
1656
+ if(ret)return ret;
1657
+ lastblock=0;
1658
+ }
1659
+
1660
+ ogg_stream_pagein(&vf->os,&og);
1661
+ }
1662
+ }
1663
+
1664
+ vf->bittrack=0.f;
1665
+ vf->samptrack=0.f;
1666
+ /* discard samples until we reach the desired position. Crossing a
1667
+ logical bitstream boundary with abandon is OK. */
1668
+ {
1669
+ /* note that halfrate could be set differently in each link, but
1670
+ vorbisfile encoforces all links are set or unset */
1671
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
1672
+ while(vf->pcm_offset<((pos>>hs)<<hs)){
1673
+ ogg_int64_t target=(pos-vf->pcm_offset)>>hs;
1674
+ long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1675
+
1676
+ if(samples>target)samples=target;
1677
+ vorbis_synthesis_read(&vf->vd,samples);
1678
+ vf->pcm_offset+=samples<<hs;
1679
+
1680
+ if(samples<target)
1681
+ if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
1682
+ vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1683
+ }
1684
+ }
1685
+ return 0;
1686
+ }
1687
+
1688
+ /* seek to a playback time relative to the decompressed pcm stream
1689
+ returns zero on success, nonzero on failure */
1690
+ int ov_time_seek(OggVorbis_File *vf,double seconds){
1691
+ /* translate time to PCM position and call ov_pcm_seek */
1692
+
1693
+ int link=-1;
1694
+ ogg_int64_t pcm_total=0;
1695
+ double time_total=0.;
1696
+
1697
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1698
+ if(!vf->seekable)return(OV_ENOSEEK);
1699
+ if(seconds<0)return(OV_EINVAL);
1700
+
1701
+ /* which bitstream section does this time offset occur in? */
1702
+ for(link=0;link<vf->links;link++){
1703
+ double addsec = ov_time_total(vf,link);
1704
+ if(seconds<time_total+addsec)break;
1705
+ time_total+=addsec;
1706
+ pcm_total+=vf->pcmlengths[link*2+1];
1707
+ }
1708
+
1709
+ if(link==vf->links)return(OV_EINVAL);
1710
+
1711
+ /* enough information to convert time offset to pcm offset */
1712
+ {
1713
+ ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1714
+ return(ov_pcm_seek(vf,target));
1715
+ }
1716
+ }
1717
+
1718
+ /* page-granularity version of ov_time_seek
1719
+ returns zero on success, nonzero on failure */
1720
+ int ov_time_seek_page(OggVorbis_File *vf,double seconds){
1721
+ /* translate time to PCM position and call ov_pcm_seek */
1722
+
1723
+ int link=-1;
1724
+ ogg_int64_t pcm_total=0;
1725
+ double time_total=0.;
1726
+
1727
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1728
+ if(!vf->seekable)return(OV_ENOSEEK);
1729
+ if(seconds<0)return(OV_EINVAL);
1730
+
1731
+ /* which bitstream section does this time offset occur in? */
1732
+ for(link=0;link<vf->links;link++){
1733
+ double addsec = ov_time_total(vf,link);
1734
+ if(seconds<time_total+addsec)break;
1735
+ time_total+=addsec;
1736
+ pcm_total+=vf->pcmlengths[link*2+1];
1737
+ }
1738
+
1739
+ if(link==vf->links)return(OV_EINVAL);
1740
+
1741
+ /* enough information to convert time offset to pcm offset */
1742
+ {
1743
+ ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1744
+ return(ov_pcm_seek_page(vf,target));
1745
+ }
1746
+ }
1747
+
1748
+ /* tell the current stream offset cursor. Note that seek followed by
1749
+ tell will likely not give the set offset due to caching */
1750
+ ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1751
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1752
+ return(vf->offset);
1753
+ }
1754
+
1755
+ /* return PCM offset (sample) of next PCM sample to be read */
1756
+ ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
1757
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1758
+ return(vf->pcm_offset);
1759
+ }
1760
+
1761
+ /* return time offset (seconds) of next PCM sample to be read */
1762
+ double ov_time_tell(OggVorbis_File *vf){
1763
+ int link=0;
1764
+ ogg_int64_t pcm_total=0;
1765
+ double time_total=0.f;
1766
+
1767
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1768
+ if(vf->seekable){
1769
+ pcm_total=ov_pcm_total(vf,-1);
1770
+ time_total=ov_time_total(vf,-1);
1771
+
1772
+ /* which bitstream section does this time offset occur in? */
1773
+ for(link=vf->links-1;link>=0;link--){
1774
+ pcm_total-=vf->pcmlengths[link*2+1];
1775
+ time_total-=ov_time_total(vf,link);
1776
+ if(vf->pcm_offset>=pcm_total)break;
1777
+ }
1778
+ }
1779
+
1780
+ return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
1781
+ }
1782
+
1783
+ /* link: -1) return the vorbis_info struct for the bitstream section
1784
+ currently being decoded
1785
+ 0-n) to request information for a specific bitstream section
1786
+
1787
+ In the case of a non-seekable bitstream, any call returns the
1788
+ current bitstream. NULL in the case that the machine is not
1789
+ initialized */
1790
+
1791
+ vorbis_info *ov_info(OggVorbis_File *vf,int link){
1792
+ if(vf->seekable){
1793
+ if(link<0)
1794
+ if(vf->ready_state>=STREAMSET)
1795
+ return vf->vi+vf->current_link;
1796
+ else
1797
+ return vf->vi;
1798
+ else
1799
+ if(link>=vf->links)
1800
+ return NULL;
1801
+ else
1802
+ return vf->vi+link;
1803
+ }else{
1804
+ return vf->vi;
1805
+ }
1806
+ }
1807
+
1808
+ /* grr, strong typing, grr, no templates/inheritence, grr */
1809
+ vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
1810
+ if(vf->seekable){
1811
+ if(link<0)
1812
+ if(vf->ready_state>=STREAMSET)
1813
+ return vf->vc+vf->current_link;
1814
+ else
1815
+ return vf->vc;
1816
+ else
1817
+ if(link>=vf->links)
1818
+ return NULL;
1819
+ else
1820
+ return vf->vc+link;
1821
+ }else{
1822
+ return vf->vc;
1823
+ }
1824
+ }
1825
+
1826
+ static int host_is_big_endian() {
1827
+ ogg_int32_t pattern = 0xfeedface; /* deadbeef */
1828
+ unsigned char *bytewise = (unsigned char *)&pattern;
1829
+ if (bytewise[0] == 0xfe) return 1;
1830
+ return 0;
1831
+ }
1832
+
1833
+ /* up to this point, everything could more or less hide the multiple
1834
+ logical bitstream nature of chaining from the toplevel application
1835
+ if the toplevel application didn't particularly care. However, at
1836
+ the point that we actually read audio back, the multiple-section
1837
+ nature must surface: Multiple bitstream sections do not necessarily
1838
+ have to have the same number of channels or sampling rate.
1839
+
1840
+ ov_read returns the sequential logical bitstream number currently
1841
+ being decoded along with the PCM data in order that the toplevel
1842
+ application can take action on channel/sample rate changes. This
1843
+ number will be incremented even for streamed (non-seekable) streams
1844
+ (for seekable streams, it represents the actual logical bitstream
1845
+ index within the physical bitstream. Note that the accessor
1846
+ functions above are aware of this dichotomy).
1847
+
1848
+ ov_read_filter is exactly the same as ov_read except that it processes
1849
+ the decoded audio data through a filter before packing it into the
1850
+ requested format. This gives greater accuracy than applying a filter
1851
+ after the audio has been converted into integral PCM.
1852
+
1853
+ input values: buffer) a buffer to hold packed PCM data for return
1854
+ length) the byte length requested to be placed into buffer
1855
+ bigendianp) should the data be packed LSB first (0) or
1856
+ MSB first (1)
1857
+ word) word size for output. currently 1 (byte) or
1858
+ 2 (16 bit short)
1859
+
1860
+ return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1861
+ 0) EOF
1862
+ n) number of bytes of PCM actually returned. The
1863
+ below works on a packet-by-packet basis, so the
1864
+ return length is not related to the 'length' passed
1865
+ in, just guaranteed to fit.
1866
+
1867
+ *section) set to the logical bitstream number */
1868
+
1869
+ long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
1870
+ int bigendianp,int word,int sgned,int *bitstream,
1871
+ void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){
1872
+ int i,j;
1873
+ int host_endian = host_is_big_endian();
1874
+ int hs;
1875
+
1876
+ float **pcm;
1877
+ long samples;
1878
+
1879
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
1880
+
1881
+ while(1){
1882
+ if(vf->ready_state==INITSET){
1883
+ samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1884
+ if(samples)break;
1885
+ }
1886
+
1887
+ /* suck in another packet */
1888
+ {
1889
+ int ret=_fetch_and_process_packet(vf,NULL,1,1);
1890
+ if(ret==OV_EOF)
1891
+ return(0);
1892
+ if(ret<=0)
1893
+ return(ret);
1894
+ }
1895
+
1896
+ }
1897
+
1898
+ if(samples>0){
1899
+
1900
+ /* yay! proceed to pack data into the byte buffer */
1901
+
1902
+ long channels=ov_info(vf,-1)->channels;
1903
+ long bytespersample=word * channels;
1904
+ vorbis_fpu_control fpu;
1905
+ if(samples>length/bytespersample)samples=length/bytespersample;
1906
+
1907
+ if(samples <= 0)
1908
+ return OV_EINVAL;
1909
+
1910
+ /* Here. */
1911
+ if(filter)
1912
+ filter(pcm,channels,samples,filter_param);
1913
+
1914
+ /* a tight loop to pack each size */
1915
+ {
1916
+ int val;
1917
+ if(word==1){
1918
+ int off=(sgned?0:128);
1919
+ vorbis_fpu_setround(&fpu);
1920
+ for(j=0;j<samples;j++)
1921
+ for(i=0;i<channels;i++){
1922
+ val=vorbis_ftoi(pcm[i][j]*128.f);
1923
+ if(val>127)val=127;
1924
+ else if(val<-128)val=-128;
1925
+ *buffer++=val+off;
1926
+ }
1927
+ vorbis_fpu_restore(fpu);
1928
+ }else{
1929
+ int off=(sgned?0:32768);
1930
+
1931
+ if(host_endian==bigendianp){
1932
+ if(sgned){
1933
+
1934
+ vorbis_fpu_setround(&fpu);
1935
+ for(i=0;i<channels;i++) { /* It's faster in this order */
1936
+ float *src=pcm[i];
1937
+ short *dest=((short *)buffer)+i;
1938
+ for(j=0;j<samples;j++) {
1939
+ val=vorbis_ftoi(src[j]*32768.f);
1940
+ if(val>32767)val=32767;
1941
+ else if(val<-32768)val=-32768;
1942
+ *dest=val;
1943
+ dest+=channels;
1944
+ }
1945
+ }
1946
+ vorbis_fpu_restore(fpu);
1947
+
1948
+ }else{
1949
+
1950
+ vorbis_fpu_setround(&fpu);
1951
+ for(i=0;i<channels;i++) {
1952
+ float *src=pcm[i];
1953
+ short *dest=((short *)buffer)+i;
1954
+ for(j=0;j<samples;j++) {
1955
+ val=vorbis_ftoi(src[j]*32768.f);
1956
+ if(val>32767)val=32767;
1957
+ else if(val<-32768)val=-32768;
1958
+ *dest=val+off;
1959
+ dest+=channels;
1960
+ }
1961
+ }
1962
+ vorbis_fpu_restore(fpu);
1963
+
1964
+ }
1965
+ }else if(bigendianp){
1966
+
1967
+ vorbis_fpu_setround(&fpu);
1968
+ for(j=0;j<samples;j++)
1969
+ for(i=0;i<channels;i++){
1970
+ val=vorbis_ftoi(pcm[i][j]*32768.f);
1971
+ if(val>32767)val=32767;
1972
+ else if(val<-32768)val=-32768;
1973
+ val+=off;
1974
+ *buffer++=(val>>8);
1975
+ *buffer++=(val&0xff);
1976
+ }
1977
+ vorbis_fpu_restore(fpu);
1978
+
1979
+ }else{
1980
+ int val;
1981
+ vorbis_fpu_setround(&fpu);
1982
+ for(j=0;j<samples;j++)
1983
+ for(i=0;i<channels;i++){
1984
+ val=vorbis_ftoi(pcm[i][j]*32768.f);
1985
+ if(val>32767)val=32767;
1986
+ else if(val<-32768)val=-32768;
1987
+ val+=off;
1988
+ *buffer++=(val&0xff);
1989
+ *buffer++=(val>>8);
1990
+ }
1991
+ vorbis_fpu_restore(fpu);
1992
+
1993
+ }
1994
+ }
1995
+ }
1996
+
1997
+ vorbis_synthesis_read(&vf->vd,samples);
1998
+ hs=vorbis_synthesis_halfrate_p(vf->vi);
1999
+ vf->pcm_offset+=(samples<<hs);
2000
+ if(bitstream)*bitstream=vf->current_link;
2001
+ return(samples*bytespersample);
2002
+ }else{
2003
+ return(samples);
2004
+ }
2005
+ }
2006
+
2007
+ long ov_read(OggVorbis_File *vf,char *buffer,int length,
2008
+ int bigendianp,int word,int sgned,int *bitstream){
2009
+ return ov_read_filter(vf, buffer, length, bigendianp, word, sgned, bitstream, NULL, NULL);
2010
+ }
2011
+
2012
+ /* input values: pcm_channels) a float vector per channel of output
2013
+ length) the sample length being read by the app
2014
+
2015
+ return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
2016
+ 0) EOF
2017
+ n) number of samples of PCM actually returned. The
2018
+ below works on a packet-by-packet basis, so the
2019
+ return length is not related to the 'length' passed
2020
+ in, just guaranteed to fit.
2021
+
2022
+ *section) set to the logical bitstream number */
2023
+
2024
+
2025
+
2026
+ long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
2027
+ int *bitstream){
2028
+
2029
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
2030
+
2031
+ while(1){
2032
+ if(vf->ready_state==INITSET){
2033
+ float **pcm;
2034
+ long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
2035
+ if(samples){
2036
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
2037
+ if(pcm_channels)*pcm_channels=pcm;
2038
+ if(samples>length)samples=length;
2039
+ vorbis_synthesis_read(&vf->vd,samples);
2040
+ vf->pcm_offset+=samples<<hs;
2041
+ if(bitstream)*bitstream=vf->current_link;
2042
+ return samples;
2043
+
2044
+ }
2045
+ }
2046
+
2047
+ /* suck in another packet */
2048
+ {
2049
+ int ret=_fetch_and_process_packet(vf,NULL,1,1);
2050
+ if(ret==OV_EOF)return(0);
2051
+ if(ret<=0)return(ret);
2052
+ }
2053
+
2054
+ }
2055
+ }
2056
+
2057
+ extern float *vorbis_window(vorbis_dsp_state *v,int W);
2058
+
2059
+ static void _ov_splice(float **pcm,float **lappcm,
2060
+ int n1, int n2,
2061
+ int ch1, int ch2,
2062
+ float *w1, float *w2){
2063
+ int i,j;
2064
+ float *w=w1;
2065
+ int n=n1;
2066
+
2067
+ if(n1>n2){
2068
+ n=n2;
2069
+ w=w2;
2070
+ }
2071
+
2072
+ /* splice */
2073
+ for(j=0;j<ch1 && j<ch2;j++){
2074
+ float *s=lappcm[j];
2075
+ float *d=pcm[j];
2076
+
2077
+ for(i=0;i<n;i++){
2078
+ float wd=w[i]*w[i];
2079
+ float ws=1.-wd;
2080
+ d[i]=d[i]*wd + s[i]*ws;
2081
+ }
2082
+ }
2083
+ /* window from zero */
2084
+ for(;j<ch2;j++){
2085
+ float *d=pcm[j];
2086
+ for(i=0;i<n;i++){
2087
+ float wd=w[i]*w[i];
2088
+ d[i]=d[i]*wd;
2089
+ }
2090
+ }
2091
+
2092
+ }
2093
+
2094
+ /* make sure vf is INITSET */
2095
+ static int _ov_initset(OggVorbis_File *vf){
2096
+ while(1){
2097
+ if(vf->ready_state==INITSET)break;
2098
+ /* suck in another packet */
2099
+ {
2100
+ int ret=_fetch_and_process_packet(vf,NULL,1,0);
2101
+ if(ret<0 && ret!=OV_HOLE)return(ret);
2102
+ }
2103
+ }
2104
+ return 0;
2105
+ }
2106
+
2107
+ /* make sure vf is INITSET and that we have a primed buffer; if
2108
+ we're crosslapping at a stream section boundary, this also makes
2109
+ sure we're sanity checking against the right stream information */
2110
+ static int _ov_initprime(OggVorbis_File *vf){
2111
+ vorbis_dsp_state *vd=&vf->vd;
2112
+ while(1){
2113
+ if(vf->ready_state==INITSET)
2114
+ if(vorbis_synthesis_pcmout(vd,NULL))break;
2115
+
2116
+ /* suck in another packet */
2117
+ {
2118
+ int ret=_fetch_and_process_packet(vf,NULL,1,0);
2119
+ if(ret<0 && ret!=OV_HOLE)return(ret);
2120
+ }
2121
+ }
2122
+ return 0;
2123
+ }
2124
+
2125
+ /* grab enough data for lapping from vf; this may be in the form of
2126
+ unreturned, already-decoded pcm, remaining PCM we will need to
2127
+ decode, or synthetic postextrapolation from last packets. */
2128
+ static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
2129
+ float **lappcm,int lapsize){
2130
+ int lapcount=0,i;
2131
+ float **pcm;
2132
+
2133
+ /* try first to decode the lapping data */
2134
+ while(lapcount<lapsize){
2135
+ int samples=vorbis_synthesis_pcmout(vd,&pcm);
2136
+ if(samples){
2137
+ if(samples>lapsize-lapcount)samples=lapsize-lapcount;
2138
+ for(i=0;i<vi->channels;i++)
2139
+ memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
2140
+ lapcount+=samples;
2141
+ vorbis_synthesis_read(vd,samples);
2142
+ }else{
2143
+ /* suck in another packet */
2144
+ int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */
2145
+ if(ret==OV_EOF)break;
2146
+ }
2147
+ }
2148
+ if(lapcount<lapsize){
2149
+ /* failed to get lapping data from normal decode; pry it from the
2150
+ postextrapolation buffering, or the second half of the MDCT
2151
+ from the last packet */
2152
+ int samples=vorbis_synthesis_lapout(&vf->vd,&pcm);
2153
+ if(samples==0){
2154
+ for(i=0;i<vi->channels;i++)
2155
+ memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
2156
+ lapcount=lapsize;
2157
+ }else{
2158
+ if(samples>lapsize-lapcount)samples=lapsize-lapcount;
2159
+ for(i=0;i<vi->channels;i++)
2160
+ memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
2161
+ lapcount+=samples;
2162
+ }
2163
+ }
2164
+ }
2165
+
2166
+ /* this sets up crosslapping of a sample by using trailing data from
2167
+ sample 1 and lapping it into the windowing buffer of sample 2 */
2168
+ int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
2169
+ vorbis_info *vi1,*vi2;
2170
+ float **lappcm;
2171
+ float **pcm;
2172
+ float *w1,*w2;
2173
+ int n1,n2,i,ret,hs1,hs2;
2174
+
2175
+ if(vf1==vf2)return(0); /* degenerate case */
2176
+ if(vf1->ready_state<OPENED)return(OV_EINVAL);
2177
+ if(vf2->ready_state<OPENED)return(OV_EINVAL);
2178
+
2179
+ /* the relevant overlap buffers must be pre-checked and pre-primed
2180
+ before looking at settings in the event that priming would cross
2181
+ a bitstream boundary. So, do it now */
2182
+
2183
+ ret=_ov_initset(vf1);
2184
+ if(ret)return(ret);
2185
+ ret=_ov_initprime(vf2);
2186
+ if(ret)return(ret);
2187
+
2188
+ vi1=ov_info(vf1,-1);
2189
+ vi2=ov_info(vf2,-1);
2190
+ hs1=ov_halfrate_p(vf1);
2191
+ hs2=ov_halfrate_p(vf2);
2192
+
2193
+ lappcm=alloca(sizeof(*lappcm)*vi1->channels);
2194
+ n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
2195
+ n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
2196
+ w1=vorbis_window(&vf1->vd,0);
2197
+ w2=vorbis_window(&vf2->vd,0);
2198
+
2199
+ for(i=0;i<vi1->channels;i++)
2200
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
2201
+
2202
+ _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
2203
+
2204
+ /* have a lapping buffer from vf1; now to splice it into the lapping
2205
+ buffer of vf2 */
2206
+ /* consolidate and expose the buffer. */
2207
+ vorbis_synthesis_lapout(&vf2->vd,&pcm);
2208
+
2209
+ #if 0
2210
+ _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
2211
+ _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
2212
+ #endif
2213
+
2214
+ /* splice */
2215
+ _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2);
2216
+
2217
+ /* done */
2218
+ return(0);
2219
+ }
2220
+
2221
+ static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
2222
+ int (*localseek)(OggVorbis_File *,ogg_int64_t)){
2223
+ vorbis_info *vi;
2224
+ float **lappcm;
2225
+ float **pcm;
2226
+ float *w1,*w2;
2227
+ int n1,n2,ch1,ch2,hs;
2228
+ int i,ret;
2229
+
2230
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
2231
+ ret=_ov_initset(vf);
2232
+ if(ret)return(ret);
2233
+ vi=ov_info(vf,-1);
2234
+ hs=ov_halfrate_p(vf);
2235
+
2236
+ ch1=vi->channels;
2237
+ n1=vorbis_info_blocksize(vi,0)>>(1+hs);
2238
+ w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are
2239
+ persistent; even if the decode state
2240
+ from this link gets dumped, this
2241
+ window array continues to exist */
2242
+
2243
+ lappcm=alloca(sizeof(*lappcm)*ch1);
2244
+ for(i=0;i<ch1;i++)
2245
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
2246
+ _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
2247
+
2248
+ /* have lapping data; seek and prime the buffer */
2249
+ ret=localseek(vf,pos);
2250
+ if(ret)return ret;
2251
+ ret=_ov_initprime(vf);
2252
+ if(ret)return(ret);
2253
+
2254
+ /* Guard against cross-link changes; they're perfectly legal */
2255
+ vi=ov_info(vf,-1);
2256
+ ch2=vi->channels;
2257
+ n2=vorbis_info_blocksize(vi,0)>>(1+hs);
2258
+ w2=vorbis_window(&vf->vd,0);
2259
+
2260
+ /* consolidate and expose the buffer. */
2261
+ vorbis_synthesis_lapout(&vf->vd,&pcm);
2262
+
2263
+ /* splice */
2264
+ _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
2265
+
2266
+ /* done */
2267
+ return(0);
2268
+ }
2269
+
2270
+ int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
2271
+ return _ov_64_seek_lap(vf,pos,ov_raw_seek);
2272
+ }
2273
+
2274
+ int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
2275
+ return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
2276
+ }
2277
+
2278
+ int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
2279
+ return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
2280
+ }
2281
+
2282
+ static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
2283
+ int (*localseek)(OggVorbis_File *,double)){
2284
+ vorbis_info *vi;
2285
+ float **lappcm;
2286
+ float **pcm;
2287
+ float *w1,*w2;
2288
+ int n1,n2,ch1,ch2,hs;
2289
+ int i,ret;
2290
+
2291
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
2292
+ ret=_ov_initset(vf);
2293
+ if(ret)return(ret);
2294
+ vi=ov_info(vf,-1);
2295
+ hs=ov_halfrate_p(vf);
2296
+
2297
+ ch1=vi->channels;
2298
+ n1=vorbis_info_blocksize(vi,0)>>(1+hs);
2299
+ w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are
2300
+ persistent; even if the decode state
2301
+ from this link gets dumped, this
2302
+ window array continues to exist */
2303
+
2304
+ lappcm=alloca(sizeof(*lappcm)*ch1);
2305
+ for(i=0;i<ch1;i++)
2306
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
2307
+ _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
2308
+
2309
+ /* have lapping data; seek and prime the buffer */
2310
+ ret=localseek(vf,pos);
2311
+ if(ret)return ret;
2312
+ ret=_ov_initprime(vf);
2313
+ if(ret)return(ret);
2314
+
2315
+ /* Guard against cross-link changes; they're perfectly legal */
2316
+ vi=ov_info(vf,-1);
2317
+ ch2=vi->channels;
2318
+ n2=vorbis_info_blocksize(vi,0)>>(1+hs);
2319
+ w2=vorbis_window(&vf->vd,0);
2320
+
2321
+ /* consolidate and expose the buffer. */
2322
+ vorbis_synthesis_lapout(&vf->vd,&pcm);
2323
+
2324
+ /* splice */
2325
+ _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
2326
+
2327
+ /* done */
2328
+ return(0);
2329
+ }
2330
+
2331
+ int ov_time_seek_lap(OggVorbis_File *vf,double pos){
2332
+ return _ov_d_seek_lap(vf,pos,ov_time_seek);
2333
+ }
2334
+
2335
+ int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
2336
+ return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
2337
+ }