MusicBCSTM.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include <iostream>
  2. #include <cpp3ds/System/I18n.hpp>
  3. #include <cpp3ds/System/FileInputStream.hpp>
  4. #include <cpp3ds/System/Sleep.hpp>
  5. #include <arpa/inet.h>
  6. #include <netinet/in.h>
  7. #include <cpp3ds/Window.hpp>
  8. #include "MusicBCSTM.hpp"
  9. namespace FreeShop {
  10. MusicBCSTM::MusicBCSTM()
  11. : m_thread(&MusicBCSTM::streamData, this)
  12. , m_isStreaming (false)
  13. , m_isPaused (false)
  14. , m_channelCount(0)
  15. {
  16. m_thread.setPriority(0x1A);
  17. }
  18. MusicBCSTM::~MusicBCSTM()
  19. {
  20. stop();
  21. }
  22. bool MusicBCSTM::openFromFile(const std::string &filename)
  23. {
  24. if (!cpp3ds::Service::isEnabled(cpp3ds::Audio))
  25. return false;
  26. stop();
  27. if (!m_file.open(filename))
  28. return false;
  29. m_isLittleEndian = true; // Default to true so initial reads are not swapped
  30. // Verify header magic value and get endianness
  31. cpp3ds::Uint32 magic = read32();
  32. if (!(m_isLittleEndian = (read16() == 0xFEFF)))
  33. magic = htonl(magic);
  34. if (magic != 0x4D545343) // "CSTM"
  35. return false;
  36. //
  37. m_file.seek(0x10);
  38. uint16_t sectionBlockCount = read16();
  39. read16();
  40. m_dataOffset = 0;
  41. m_infoOffset = 0;
  42. for (int i = 0; i < sectionBlockCount; i++)
  43. {
  44. int sec = read16();
  45. read16(); // padding
  46. uint32_t off = read32();
  47. read32(); // size
  48. if (sec == InfoBlock)
  49. m_infoOffset = off;
  50. else if (sec == DataBlock)
  51. m_dataOffset = off;
  52. }
  53. if (!m_infoOffset || !m_dataOffset)
  54. return false;
  55. m_file.seek(m_infoOffset + 0x20);
  56. if (read8() != 2)
  57. {
  58. cpp3ds::err() << "Encoding isn't DSP ADPCM: " << filename << std::endl;
  59. return false;
  60. }
  61. m_looping = read8();
  62. m_channelCount = read8();
  63. if (m_channelCount > 2)
  64. {
  65. cpp3ds::err() << "Channel count (" << m_channelCount << ") isn't supported: " << filename << std::endl;
  66. return false;
  67. }
  68. m_file.seek(m_infoOffset + 0x24);
  69. m_sampleRate = read32();
  70. uint32_t loopPos = read32();
  71. uint32_t loopEnd = read32();
  72. m_blockCount = read32();
  73. m_blockSize = read32();
  74. m_blockSampleCount = read32();
  75. read32(); // last block used bytes
  76. m_lastBlockSampleCount = read32();
  77. m_lastBlockSize = read32();
  78. m_blockLoopStart = loopPos / m_blockSampleCount;
  79. m_blockLoopEnd = (loopEnd % m_blockSampleCount ? m_blockCount : loopEnd / m_blockSampleCount);
  80. while (read32() != ChannelInfo);
  81. fileAdvance(read32() + m_channelCount*8 - 12);
  82. #ifdef _3DS
  83. // Get ADPCM data
  84. for (int i = 0; i < m_channelCount; i++)
  85. {
  86. m_file.read(m_adpcmCoefs[i], sizeof(uint16_t) * 16);
  87. m_file.read(&m_adpcmData[i][0], sizeof(ndspAdpcmData)); // Beginning Context
  88. m_file.read(&m_adpcmData[i][1], sizeof(ndspAdpcmData)); // Loop context
  89. read16(); // skip padding
  90. }
  91. #endif
  92. m_currentBlock = 0;
  93. m_file.seek(m_dataOffset + 0x20);
  94. return true;
  95. }
  96. void MusicBCSTM::play()
  97. {
  98. if (m_isPaused)
  99. {
  100. #ifdef _3DS
  101. for (int i = 0; i < m_channelCount; ++i)
  102. ndspChnSetPaused(m_channel[i], false);
  103. #endif
  104. m_isPaused = false;
  105. return;
  106. }
  107. if (m_isStreaming)
  108. stop();
  109. #ifdef _3DS
  110. for (int i = 0; i < m_channelCount; ++i)
  111. {
  112. {
  113. cpp3ds::Lock lock(cpp3ds::g_activeNdspChannelsMutex);
  114. m_channel[i] = 0;
  115. while (m_channel[i] < 24 && ((cpp3ds::g_activeNdspChannels >> m_channel[i]) & 1))
  116. m_channel[i]++;
  117. if (m_channel[i] == 24)
  118. {
  119. cpp3ds::err() << "Failed to play audio stream: all channels are in use." << std::endl;
  120. return;
  121. }
  122. cpp3ds::g_activeNdspChannels |= 1 << m_channel[i];
  123. ndspChnWaveBufClear(m_channel[i]);
  124. }
  125. static float mix[16];
  126. ndspChnSetFormat(m_channel[i], NDSP_FORMAT_ADPCM | NDSP_3D_SURROUND_PREPROCESSED);
  127. ndspChnSetRate(m_channel[i], m_sampleRate);
  128. if (m_channelCount == 1)
  129. mix[0] = mix[1] = 0.5f;
  130. else if (m_channelCount == 2)
  131. {
  132. if (i == 0)
  133. {
  134. mix[0] = 0.8f;
  135. mix[1] = 0.0f;
  136. mix[2] = 0.2f;
  137. mix[3] = 0.0f;
  138. } else
  139. {
  140. mix[0] = 0.0f;
  141. mix[1] = 0.8f;
  142. mix[2] = 0.0f;
  143. mix[3] = 0.2f;
  144. }
  145. }
  146. ndspChnSetMix(m_channel[i], mix);
  147. ndspChnSetAdpcmCoefs(m_channel[i], m_adpcmCoefs[i]);
  148. for (int j = 0; j < BufferCount; j ++)
  149. {
  150. memset(&m_waveBuf[i][j], 0, sizeof(ndspWaveBuf));
  151. m_waveBuf[i][j].status = NDSP_WBUF_DONE;
  152. m_bufferData[i][j].resize(m_blockSize);
  153. }
  154. }
  155. #endif
  156. m_isStreaming = true;
  157. m_thread.launch();
  158. }
  159. void MusicBCSTM::pause()
  160. {
  161. cpp3ds::Lock lock(m_mutex);
  162. if (!m_isStreaming)
  163. return;
  164. m_isPaused = true;
  165. #ifdef _3DS
  166. for (int i = 0; i < m_channelCount; ++i)
  167. ndspChnSetPaused(m_channel[i], true);
  168. #endif
  169. }
  170. void MusicBCSTM::stop()
  171. {
  172. if (!m_isStreaming)
  173. return;
  174. {
  175. cpp3ds::Lock lock(m_mutex);
  176. m_isStreaming = false;
  177. }
  178. m_thread.wait();
  179. #ifdef _3DS
  180. cpp3ds::Lock lock(cpp3ds::g_activeNdspChannelsMutex);
  181. for (int i = 0; i < m_channelCount; ++i)
  182. {
  183. ndspChnWaveBufClear(m_channel[i]);
  184. cpp3ds::g_activeNdspChannels &= ~(1 << m_channel[i]);
  185. }
  186. #endif
  187. }
  188. void MusicBCSTM::streamData()
  189. {
  190. bool isPaused = false;
  191. while (1)
  192. {
  193. {
  194. cpp3ds::Lock lock(m_mutex);
  195. isPaused = m_isPaused;
  196. if (!m_isStreaming)
  197. break;
  198. }
  199. if (!isPaused)
  200. {
  201. fillBuffers();
  202. }
  203. cpp3ds::sleep(cpp3ds::milliseconds(100));
  204. }
  205. }
  206. uint32_t MusicBCSTM::read32()
  207. {
  208. uint32_t v;
  209. m_file.read(&v, sizeof(v));
  210. return (m_isLittleEndian ? v : htonl(v));
  211. }
  212. uint16_t MusicBCSTM::read16()
  213. {
  214. uint16_t v;
  215. m_file.read(&v, sizeof(v));
  216. return (m_isLittleEndian ? v : htons(v));
  217. }
  218. uint8_t MusicBCSTM::read8()
  219. {
  220. uint8_t v;
  221. m_file.read(&v, sizeof(v));
  222. return v;
  223. }
  224. void MusicBCSTM::fillBuffers()
  225. {
  226. #ifdef _3DS
  227. for (int bufIndex = 0; bufIndex < BufferCount; ++bufIndex)
  228. {
  229. if (m_waveBuf[0][bufIndex].status != NDSP_WBUF_DONE)
  230. continue;
  231. if (m_channelCount == 2 && m_waveBuf[1][bufIndex].status != NDSP_WBUF_DONE)
  232. continue;
  233. if (m_currentBlock == m_blockLoopEnd)
  234. {
  235. m_currentBlock = m_blockLoopStart;
  236. m_file.seek(m_dataOffset + 0x20 + m_blockSize*m_channelCount*m_blockLoopStart);
  237. }
  238. for (int channelIndex = 0; channelIndex < m_channelCount; ++channelIndex)
  239. {
  240. ndspWaveBuf *buf = &m_waveBuf[channelIndex][bufIndex];
  241. memset(buf, 0, sizeof(ndspWaveBuf));
  242. buf->data_adpcm = m_bufferData[channelIndex][bufIndex].data();
  243. m_file.read(buf->data_adpcm, (m_currentBlock == m_blockCount-1) ? m_lastBlockSize : m_blockSize);
  244. DSP_FlushDataCache(buf->data_adpcm, m_blockSize);
  245. if (m_currentBlock == 0)
  246. buf->adpcm_data = &m_adpcmData[channelIndex][0];
  247. else if (m_currentBlock == m_blockLoopStart)
  248. buf->adpcm_data = &m_adpcmData[channelIndex][1];
  249. if (m_currentBlock == m_blockCount-1)
  250. buf->nsamples = m_lastBlockSampleCount;
  251. else
  252. buf->nsamples = m_blockSampleCount;
  253. ndspChnWaveBufAdd(m_channel[channelIndex], buf);
  254. }
  255. m_currentBlock++;
  256. }
  257. #endif
  258. }
  259. bool MusicBCSTM::fileAdvance(uint64_t byteSize)
  260. {
  261. uint64_t seekPosition = m_file.tell() + byteSize;
  262. return (m_file.seek(seekPosition) == seekPosition);
  263. }
  264. } // namespace FreeShop