🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

395 lines
11 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include "backends/wave.h"
  22. #include <cstdlib>
  23. #include <cstdio>
  24. #include <memory.h>
  25. #include <cerrno>
  26. #include <chrono>
  27. #include <thread>
  28. #include <vector>
  29. #include <functional>
  30. #include "alMain.h"
  31. #include "alu.h"
  32. #include "alconfig.h"
  33. #include "compat.h"
  34. namespace {
  35. using std::chrono::seconds;
  36. using std::chrono::milliseconds;
  37. using std::chrono::nanoseconds;
  38. constexpr ALCchar waveDevice[] = "Wave File Writer";
  39. constexpr ALubyte SUBTYPE_PCM[]{
  40. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
  41. 0x00, 0x38, 0x9b, 0x71
  42. };
  43. constexpr ALubyte SUBTYPE_FLOAT[]{
  44. 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
  45. 0x00, 0x38, 0x9b, 0x71
  46. };
  47. constexpr ALubyte SUBTYPE_BFORMAT_PCM[]{
  48. 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
  49. 0xca, 0x00, 0x00, 0x00
  50. };
  51. constexpr ALubyte SUBTYPE_BFORMAT_FLOAT[]{
  52. 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
  53. 0xca, 0x00, 0x00, 0x00
  54. };
  55. void fwrite16le(ALushort val, FILE *f)
  56. {
  57. ALubyte data[2]{ static_cast<ALubyte>(val&0xff), static_cast<ALubyte>((val>>8)&0xff) };
  58. fwrite(data, 1, 2, f);
  59. }
  60. void fwrite32le(ALuint val, FILE *f)
  61. {
  62. ALubyte data[4]{ static_cast<ALubyte>(val&0xff), static_cast<ALubyte>((val>>8)&0xff),
  63. static_cast<ALubyte>((val>>16)&0xff), static_cast<ALubyte>((val>>24)&0xff) };
  64. fwrite(data, 1, 4, f);
  65. }
  66. struct WaveBackend final : public BackendBase {
  67. WaveBackend(ALCdevice *device) noexcept : BackendBase{device} { }
  68. ~WaveBackend() override;
  69. int mixerProc();
  70. ALCenum open(const ALCchar *name) override;
  71. ALCboolean reset() override;
  72. ALCboolean start() override;
  73. void stop() override;
  74. FILE *mFile{nullptr};
  75. long mDataStart{-1};
  76. al::vector<ALbyte> mBuffer;
  77. std::atomic<bool> mKillNow{true};
  78. std::thread mThread;
  79. static constexpr inline const char *CurrentPrefix() noexcept { return "WaveBackend::"; }
  80. DEF_NEWDEL(WaveBackend)
  81. };
  82. WaveBackend::~WaveBackend()
  83. {
  84. if(mFile)
  85. fclose(mFile);
  86. mFile = nullptr;
  87. }
  88. int WaveBackend::mixerProc()
  89. {
  90. const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2};
  91. althrd_setname(MIXER_THREAD_NAME);
  92. const ALsizei frameSize{mDevice->frameSizeFromFmt()};
  93. int64_t done{0};
  94. auto start = std::chrono::steady_clock::now();
  95. while(!mKillNow.load(std::memory_order_acquire) &&
  96. mDevice->Connected.load(std::memory_order_acquire))
  97. {
  98. auto now = std::chrono::steady_clock::now();
  99. /* This converts from nanoseconds to nanosamples, then to samples. */
  100. int64_t avail{std::chrono::duration_cast<seconds>((now-start) *
  101. mDevice->Frequency).count()};
  102. if(avail-done < mDevice->UpdateSize)
  103. {
  104. std::this_thread::sleep_for(restTime);
  105. continue;
  106. }
  107. while(avail-done >= mDevice->UpdateSize)
  108. {
  109. lock();
  110. aluMixData(mDevice, mBuffer.data(), mDevice->UpdateSize);
  111. unlock();
  112. done += mDevice->UpdateSize;
  113. if(!IS_LITTLE_ENDIAN)
  114. {
  115. const ALsizei bytesize{mDevice->bytesFromFmt()};
  116. ALsizei i;
  117. if(bytesize == 2)
  118. {
  119. ALushort *samples = reinterpret_cast<ALushort*>(mBuffer.data());
  120. const auto len = static_cast<ALsizei>(mBuffer.size() / 2);
  121. for(i = 0;i < len;i++)
  122. {
  123. ALushort samp = samples[i];
  124. samples[i] = (samp>>8) | (samp<<8);
  125. }
  126. }
  127. else if(bytesize == 4)
  128. {
  129. ALuint *samples = reinterpret_cast<ALuint*>(mBuffer.data());
  130. const auto len = static_cast<ALsizei>(mBuffer.size() / 4);
  131. for(i = 0;i < len;i++)
  132. {
  133. ALuint samp = samples[i];
  134. samples[i] = (samp>>24) | ((samp>>8)&0x0000ff00) |
  135. ((samp<<8)&0x00ff0000) | (samp<<24);
  136. }
  137. }
  138. }
  139. size_t fs{fwrite(mBuffer.data(), frameSize, mDevice->UpdateSize, mFile)};
  140. (void)fs;
  141. if(ferror(mFile))
  142. {
  143. ERR("Error writing to file\n");
  144. aluHandleDisconnect(mDevice, "Failed to write playback samples");
  145. break;
  146. }
  147. }
  148. /* For every completed second, increment the start time and reduce the
  149. * samples done. This prevents the difference between the start time
  150. * and current time from growing too large, while maintaining the
  151. * correct number of samples to render.
  152. */
  153. if(done >= mDevice->Frequency)
  154. {
  155. seconds s{done/mDevice->Frequency};
  156. start += s;
  157. done -= mDevice->Frequency*s.count();
  158. }
  159. }
  160. return 0;
  161. }
  162. ALCenum WaveBackend::open(const ALCchar *name)
  163. {
  164. const char *fname{GetConfigValue(nullptr, "wave", "file", "")};
  165. if(!fname[0]) return ALC_INVALID_VALUE;
  166. if(!name)
  167. name = waveDevice;
  168. else if(strcmp(name, waveDevice) != 0)
  169. return ALC_INVALID_VALUE;
  170. #ifdef _WIN32
  171. {
  172. std::wstring wname = utf8_to_wstr(fname);
  173. mFile = _wfopen(wname.c_str(), L"wb");
  174. }
  175. #else
  176. mFile = fopen(fname, "wb");
  177. #endif
  178. if(!mFile)
  179. {
  180. ERR("Could not open file '%s': %s\n", fname, strerror(errno));
  181. return ALC_INVALID_VALUE;
  182. }
  183. mDevice->DeviceName = name;
  184. return ALC_NO_ERROR;
  185. }
  186. ALCboolean WaveBackend::reset()
  187. {
  188. ALuint channels=0, bytes=0, chanmask=0;
  189. int isbformat = 0;
  190. size_t val;
  191. fseek(mFile, 0, SEEK_SET);
  192. clearerr(mFile);
  193. if(GetConfigValueBool(nullptr, "wave", "bformat", 0))
  194. {
  195. mDevice->FmtChans = DevFmtAmbi3D;
  196. mDevice->mAmbiOrder = 1;
  197. }
  198. switch(mDevice->FmtType)
  199. {
  200. case DevFmtByte:
  201. mDevice->FmtType = DevFmtUByte;
  202. break;
  203. case DevFmtUShort:
  204. mDevice->FmtType = DevFmtShort;
  205. break;
  206. case DevFmtUInt:
  207. mDevice->FmtType = DevFmtInt;
  208. break;
  209. case DevFmtUByte:
  210. case DevFmtShort:
  211. case DevFmtInt:
  212. case DevFmtFloat:
  213. break;
  214. }
  215. switch(mDevice->FmtChans)
  216. {
  217. case DevFmtMono: chanmask = 0x04; break;
  218. case DevFmtStereo: chanmask = 0x01 | 0x02; break;
  219. case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
  220. case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
  221. case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
  222. case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
  223. case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
  224. case DevFmtAmbi3D:
  225. /* .amb output requires FuMa */
  226. mDevice->mAmbiOrder = mini(mDevice->mAmbiOrder, 3);
  227. mDevice->mAmbiLayout = AmbiLayout::FuMa;
  228. mDevice->mAmbiScale = AmbiNorm::FuMa;
  229. isbformat = 1;
  230. chanmask = 0;
  231. break;
  232. }
  233. bytes = mDevice->bytesFromFmt();
  234. channels = mDevice->channelsFromFmt();
  235. rewind(mFile);
  236. fputs("RIFF", mFile);
  237. fwrite32le(0xFFFFFFFF, mFile); // 'RIFF' header len; filled in at close
  238. fputs("WAVE", mFile);
  239. fputs("fmt ", mFile);
  240. fwrite32le(40, mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
  241. // 16-bit val, format type id (extensible: 0xFFFE)
  242. fwrite16le(0xFFFE, mFile);
  243. // 16-bit val, channel count
  244. fwrite16le(channels, mFile);
  245. // 32-bit val, frequency
  246. fwrite32le(mDevice->Frequency, mFile);
  247. // 32-bit val, bytes per second
  248. fwrite32le(mDevice->Frequency * channels * bytes, mFile);
  249. // 16-bit val, frame size
  250. fwrite16le(channels * bytes, mFile);
  251. // 16-bit val, bits per sample
  252. fwrite16le(bytes * 8, mFile);
  253. // 16-bit val, extra byte count
  254. fwrite16le(22, mFile);
  255. // 16-bit val, valid bits per sample
  256. fwrite16le(bytes * 8, mFile);
  257. // 32-bit val, channel mask
  258. fwrite32le(chanmask, mFile);
  259. // 16 byte GUID, sub-type format
  260. val = fwrite((mDevice->FmtType == DevFmtFloat) ?
  261. (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
  262. (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, mFile);
  263. (void)val;
  264. fputs("data", mFile);
  265. fwrite32le(0xFFFFFFFF, mFile); // 'data' header len; filled in at close
  266. if(ferror(mFile))
  267. {
  268. ERR("Error writing header: %s\n", strerror(errno));
  269. return ALC_FALSE;
  270. }
  271. mDataStart = ftell(mFile);
  272. SetDefaultWFXChannelOrder(mDevice);
  273. const ALuint bufsize{mDevice->frameSizeFromFmt() * mDevice->UpdateSize};
  274. mBuffer.resize(bufsize);
  275. return ALC_TRUE;
  276. }
  277. ALCboolean WaveBackend::start()
  278. {
  279. try {
  280. mKillNow.store(false, std::memory_order_release);
  281. mThread = std::thread{std::mem_fn(&WaveBackend::mixerProc), this};
  282. return ALC_TRUE;
  283. }
  284. catch(std::exception& e) {
  285. ERR("Failed to start mixing thread: %s\n", e.what());
  286. }
  287. catch(...) {
  288. }
  289. return ALC_FALSE;
  290. }
  291. void WaveBackend::stop()
  292. {
  293. if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
  294. return;
  295. mThread.join();
  296. long size{ftell(mFile)};
  297. if(size > 0)
  298. {
  299. long dataLen{size - mDataStart};
  300. if(fseek(mFile, mDataStart-4, SEEK_SET) == 0)
  301. fwrite32le(dataLen, mFile); // 'data' header len
  302. if(fseek(mFile, 4, SEEK_SET) == 0)
  303. fwrite32le(size-8, mFile); // 'WAVE' header len
  304. }
  305. }
  306. } // namespace
  307. bool WaveBackendFactory::init()
  308. { return true; }
  309. bool WaveBackendFactory::querySupport(BackendType type)
  310. { return type == BackendType::Playback; }
  311. void WaveBackendFactory::probe(DevProbe type, std::string *outnames)
  312. {
  313. switch(type)
  314. {
  315. case DevProbe::Playback:
  316. /* Includes null char. */
  317. outnames->append(waveDevice, sizeof(waveDevice));
  318. break;
  319. case DevProbe::Capture:
  320. break;
  321. }
  322. }
  323. BackendPtr WaveBackendFactory::createBackend(ALCdevice *device, BackendType type)
  324. {
  325. if(type == BackendType::Playback)
  326. return BackendPtr{new WaveBackend{device}};
  327. return nullptr;
  328. }
  329. BackendFactory &WaveBackendFactory::getFactory()
  330. {
  331. static WaveBackendFactory factory{};
  332. return factory;
  333. }