1
0

SampleFormatVorbis.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * SampleFormatVorbis.cpp
  3. * ----------------------
  4. * Purpose: Vorbis sample import
  5. * Notes :
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "Sndfile.h"
  11. #ifndef MODPLUG_NO_FILESAVE
  12. #include "../common/mptFileIO.h"
  13. #endif
  14. #include "../common/misc_util.h"
  15. #include "Tagging.h"
  16. #include "Loaders.h"
  17. #include "../common/FileReader.h"
  18. #include "modsmp_ctrl.h"
  19. #include "openmpt/soundbase/Copy.hpp"
  20. #include "mpt/audio/span.hpp"
  21. #include "../soundlib/ModSampleCopy.h"
  22. //#include "mpt/crc/crc.hpp"
  23. #include "OggStream.h"
  24. #ifdef MPT_WITH_OGG
  25. #if MPT_COMPILER_CLANG
  26. #pragma clang diagnostic push
  27. #pragma clang diagnostic ignored "-Wreserved-id-macro"
  28. #endif // MPT_COMPILER_CLANG
  29. #include <ogg/ogg.h>
  30. #if MPT_COMPILER_CLANG
  31. #pragma clang diagnostic pop
  32. #endif // MPT_COMPILER_CLANG
  33. #endif // MPT_WITH_OGG
  34. #if defined(MPT_WITH_VORBIS)
  35. #if MPT_COMPILER_CLANG
  36. #pragma clang diagnostic push
  37. #pragma clang diagnostic ignored "-Wreserved-id-macro"
  38. #endif // MPT_COMPILER_CLANG
  39. #include <vorbis/codec.h>
  40. #if MPT_COMPILER_CLANG
  41. #pragma clang diagnostic pop
  42. #endif // MPT_COMPILER_CLANG
  43. #endif // MPT_WITH_VORBIS
  44. #if defined(MPT_WITH_VORBISFILE)
  45. #if MPT_COMPILER_CLANG
  46. #pragma clang diagnostic push
  47. #pragma clang diagnostic ignored "-Wreserved-id-macro"
  48. #endif // MPT_COMPILER_CLANG
  49. #include <vorbis/vorbisfile.h>
  50. #if MPT_COMPILER_CLANG
  51. #pragma clang diagnostic pop
  52. #endif // MPT_COMPILER_CLANG
  53. #endif // MPT_WITH_VORBISFILE
  54. #ifdef MPT_WITH_STBVORBIS
  55. #include <stb_vorbis/stb_vorbis.c>
  56. #endif // MPT_WITH_STBVORBIS
  57. OPENMPT_NAMESPACE_BEGIN
  58. ////////////////////////////////////////////////////////////////////////////////
  59. // Vorbis
  60. #if defined(MPT_WITH_VORBISFILE)
  61. static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource)
  62. {
  63. FileReader &file = *static_cast<FileReader*>(datasource);
  64. return file.ReadRaw(mpt::span(mpt::void_cast<std::byte*>(ptr), size * nmemb)).size() / size;
  65. }
  66. static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence)
  67. {
  68. FileReader &file = *static_cast<FileReader*>(datasource);
  69. switch(whence)
  70. {
  71. case SEEK_SET:
  72. {
  73. if(!mpt::in_range<FileReader::off_t>(offset))
  74. {
  75. return -1;
  76. }
  77. return file.Seek(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
  78. }
  79. break;
  80. case SEEK_CUR:
  81. {
  82. if(offset < 0)
  83. {
  84. if(offset == std::numeric_limits<ogg_int64_t>::min())
  85. {
  86. return -1;
  87. }
  88. if(!mpt::in_range<FileReader::off_t>(0-offset))
  89. {
  90. return -1;
  91. }
  92. return file.SkipBack(mpt::saturate_cast<FileReader::off_t>(0 - offset)) ? 0 : -1;
  93. } else
  94. {
  95. if(!mpt::in_range<FileReader::off_t>(offset))
  96. {
  97. return -1;
  98. }
  99. return file.Skip(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
  100. }
  101. }
  102. break;
  103. case SEEK_END:
  104. {
  105. if(!mpt::in_range<FileReader::off_t>(offset))
  106. {
  107. return -1;
  108. }
  109. if(!mpt::in_range<FileReader::off_t>(file.GetLength() + offset))
  110. {
  111. return -1;
  112. }
  113. return file.Seek(mpt::saturate_cast<FileReader::off_t>(file.GetLength() + offset)) ? 0 : -1;
  114. }
  115. break;
  116. default:
  117. return -1;
  118. }
  119. }
  120. static long VorbisfileFilereaderTell(void *datasource)
  121. {
  122. FileReader &file = *static_cast<FileReader*>(datasource);
  123. MPT_MAYBE_CONSTANT_IF(!mpt::in_range<long>(file.GetPosition()))
  124. {
  125. return -1;
  126. }
  127. return static_cast<long>(file.GetPosition());
  128. }
  129. #if defined(MPT_WITH_VORBIS)
  130. static mpt::ustring UStringFromVorbis(const char *str)
  131. {
  132. return str ? mpt::ToUnicode(mpt::Charset::UTF8, str) : mpt::ustring();
  133. }
  134. #endif // MPT_WITH_VORBIS
  135. static FileTags GetVorbisFileTags(OggVorbis_File &vf)
  136. {
  137. FileTags tags;
  138. #if defined(MPT_WITH_VORBIS)
  139. vorbis_comment *vc = ov_comment(&vf, -1);
  140. if(!vc)
  141. {
  142. return tags;
  143. }
  144. tags.encoder = UStringFromVorbis(vorbis_comment_query(vc, "ENCODER", 0));
  145. tags.title = UStringFromVorbis(vorbis_comment_query(vc, "TITLE", 0));
  146. tags.comments = UStringFromVorbis(vorbis_comment_query(vc, "DESCRIPTION", 0));
  147. tags.bpm = UStringFromVorbis(vorbis_comment_query(vc, "BPM", 0)); // non-standard
  148. tags.artist = UStringFromVorbis(vorbis_comment_query(vc, "ARTIST", 0));
  149. tags.album = UStringFromVorbis(vorbis_comment_query(vc, "ALBUM", 0));
  150. tags.trackno = UStringFromVorbis(vorbis_comment_query(vc, "TRACKNUMBER", 0));
  151. tags.year = UStringFromVorbis(vorbis_comment_query(vc, "DATE", 0));
  152. tags.url = UStringFromVorbis(vorbis_comment_query(vc, "CONTACT", 0));
  153. tags.genre = UStringFromVorbis(vorbis_comment_query(vc, "GENRE", 0));
  154. #else // !MPT_WITH_VORBIS
  155. MPT_UNREFERENCED_PARAMETER(vf);
  156. #endif // MPT_WITH_VORBIS
  157. return tags;
  158. }
  159. #endif // MPT_WITH_VORBISFILE
  160. bool CSoundFile::ReadVorbisSample(SAMPLEINDEX sample, FileReader &file)
  161. {
  162. #if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS)
  163. file.Rewind();
  164. int rate = 0;
  165. int channels = 0;
  166. std::vector<int16> raw_sample_data;
  167. std::string sampleName;
  168. #endif // VORBIS
  169. #if defined(MPT_WITH_VORBISFILE)
  170. bool unsupportedSample = false;
  171. ov_callbacks callbacks = {
  172. &VorbisfileFilereaderRead,
  173. &VorbisfileFilereaderSeek,
  174. NULL,
  175. &VorbisfileFilereaderTell
  176. };
  177. OggVorbis_File vf;
  178. MemsetZero(vf);
  179. if(ov_open_callbacks(&file, &vf, NULL, 0, callbacks) == 0)
  180. {
  181. if(ov_streams(&vf) == 1)
  182. { // we do not support chained vorbis samples
  183. vorbis_info *vi = ov_info(&vf, -1);
  184. if(vi && vi->rate > 0 && vi->channels > 0)
  185. {
  186. sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(GetVorbisFileTags(vf)));
  187. rate = vi->rate;
  188. channels = vi->channels;
  189. std::size_t offset = 0;
  190. int current_section = 0;
  191. long decodedSamples = 0;
  192. bool eof = false;
  193. if(auto length = ov_pcm_total(&vf, 0); length != OV_EINVAL)
  194. raw_sample_data.reserve(std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast<SmpLength>(length)) * std::clamp(channels, 1, 2));
  195. while(!eof)
  196. {
  197. float **output = nullptr;
  198. long ret = ov_read_float(&vf, &output, 1024, &current_section);
  199. if(ret == 0)
  200. {
  201. eof = true;
  202. } else if(ret < 0)
  203. {
  204. // stream error, just try to continue
  205. } else
  206. {
  207. decodedSamples = ret;
  208. if(decodedSamples > 0 && (channels == 1 || channels == 2))
  209. {
  210. raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples));
  211. CopyAudio(mpt::audio_span_interleaved(raw_sample_data.data() + (offset * channels), channels, decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples));
  212. offset += decodedSamples;
  213. if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH)
  214. {
  215. break;
  216. }
  217. }
  218. }
  219. }
  220. } else
  221. {
  222. unsupportedSample = true;
  223. }
  224. } else
  225. {
  226. unsupportedSample = true;
  227. }
  228. ov_clear(&vf);
  229. } else
  230. {
  231. unsupportedSample = true;
  232. }
  233. if(unsupportedSample)
  234. {
  235. return false;
  236. }
  237. #elif defined(MPT_WITH_STBVORBIS)
  238. // NOTE/TODO: stb_vorbis does not handle inferred negative PCM sample position
  239. // at stream start. (See
  240. // <https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-132000A.2>). This
  241. // means that, for remuxed and re-aligned/cutted (at stream start) Vorbis
  242. // files, stb_vorbis will include superfluous samples at the beginning.
  243. FileReader::PinnedView fileView = file.GetPinnedView();
  244. const std::byte* data = fileView.data();
  245. std::size_t dataLeft = fileView.size();
  246. std::size_t offset = 0;
  247. int consumed = 0;
  248. int error = 0;
  249. stb_vorbis *vorb = stb_vorbis_open_pushdata(mpt::byte_cast<const unsigned char*>(data), mpt::saturate_cast<int>(dataLeft), &consumed, &error, nullptr);
  250. file.Skip(consumed);
  251. data += consumed;
  252. dataLeft -= consumed;
  253. if(!vorb)
  254. {
  255. return false;
  256. }
  257. rate = stb_vorbis_get_info(vorb).sample_rate;
  258. channels = stb_vorbis_get_info(vorb).channels;
  259. if(rate <= 0 || channels <= 0)
  260. {
  261. return false;
  262. }
  263. while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0)))
  264. {
  265. int frame_channels = 0;
  266. int decodedSamples = 0;
  267. float **output = nullptr;
  268. consumed = stb_vorbis_decode_frame_pushdata(vorb, mpt::byte_cast<const unsigned char*>(data), mpt::saturate_cast<int>(dataLeft), &frame_channels, &output, &decodedSamples);
  269. file.Skip(consumed);
  270. data += consumed;
  271. dataLeft -= consumed;
  272. LimitMax(frame_channels, channels);
  273. if(decodedSamples > 0 && (frame_channels == 1 || frame_channels == 2))
  274. {
  275. raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples));
  276. CopyAudio(mpt::audio_span_interleaved(raw_sample_data.data() + (offset * channels), channels, decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples));
  277. offset += decodedSamples;
  278. if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH)
  279. {
  280. break;
  281. }
  282. }
  283. error = stb_vorbis_get_error(vorb);
  284. }
  285. stb_vorbis_close(vorb);
  286. #endif // VORBIS
  287. #if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS)
  288. if(rate <= 0 || channels <= 0 || raw_sample_data.empty())
  289. {
  290. return false;
  291. }
  292. DestroySampleThreadsafe(sample);
  293. ModSample &mptSample = Samples[sample];
  294. mptSample.Initialize();
  295. mptSample.nC5Speed = rate;
  296. mptSample.nLength = std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast<SmpLength>(raw_sample_data.size() / channels));
  297. mptSample.uFlags.set(CHN_16BIT);
  298. mptSample.uFlags.set(CHN_STEREO, channels == 2);
  299. if(!mptSample.AllocateSample())
  300. {
  301. return false;
  302. }
  303. if(raw_sample_data.size() / channels > MAX_SAMPLE_LENGTH)
  304. {
  305. AddToLog(LogWarning, U_("Sample has been truncated!"));
  306. }
  307. std::copy(raw_sample_data.begin(), raw_sample_data.begin() + mptSample.nLength * channels, mptSample.sample16());
  308. mptSample.Convert(MOD_TYPE_IT, GetType());
  309. mptSample.PrecomputeLoops(*this, false);
  310. m_szNames[sample] = sampleName;
  311. return true;
  312. #else // !VORBIS
  313. MPT_UNREFERENCED_PARAMETER(sample);
  314. MPT_UNREFERENCED_PARAMETER(file);
  315. return false;
  316. #endif // VORBIS
  317. }
  318. OPENMPT_NAMESPACE_END