void Sound::play() { if (!m_buffer || m_buffer->getSampleCount() == 0) return; if (getStatus() == Playing) stop(); m_channel = 0; while (m_channel < 24 && ndspChnIsPlaying(m_channel)) m_channel++; if (m_channel == 24) { err() << "Sound::play() failed because all channels are in use." << std::endl; m_channel = -1; return; } setPlayingOffset(m_pauseOffset); if (m_pauseOffset != Time::Zero) m_pauseOffset = Time::Zero; u32 size = sizeof(Int16) * m_buffer->getSampleCount(); ndspChnReset(m_channel); ndspChnSetInterp(m_channel, NDSP_INTERP_POLYPHASE); ndspChnSetRate(m_channel, float(m_buffer->getSampleRate())); ndspChnSetFormat(m_channel, (m_buffer->getChannelCount() == 1) ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16); DSP_FlushDataCache((u8*)m_buffer->getSamples(), size); ndspChnWaveBufAdd(m_channel, &m_ndspWaveBuf); }
void streamWAV(void* arg){ // Fetching cachePackage struct from main thread cachePackage* pack = (cachePackage*)arg; while(1) { // Waiting for updateStream event svcWaitSynchronization(updateStream, U64_MAX); svcClearEvent(updateStream); // Close the thread if closeStream event received if(closeStream){ closeStream = false; svcExitThread(); } // Check if the current stream is paused or not Music* src = pack->song; Socket* Client = pack->client; if (src->isPlaying){ // Check if a free buffer is available if (src->wavebuf2 == NULL){ // Check if file reached EOF if (src->audio_pointer >= src->size){ // Check if playback ended if (!ndspChnIsPlaying(src->ch)){ src->isPlaying = false; src->tick = (osGetTime()-src->tick); } continue; } // Swap audiobuffers u8* tmp = src->audiobuf; src->audiobuf = src->audiobuf2; src->audiobuf2 = tmp; // Create a new block for DSP service u32 bytesRead; src->wavebuf2 = (ndspWaveBuf*)calloc(1,sizeof(ndspWaveBuf)); createDspBlock(src->wavebuf2, src->bytepersample, src->mem_size, 0, (u32*)src->audiobuf); populatePurgeTable(src, src->wavebuf2); ndspChnWaveBufAdd(src->ch, src->wavebuf2); socketSend(Client, "exec2:0000"); u32 processedBytes = 0; netSize = 0; while (netSize <= 0) heapRecv(Client, 2048); while (processedBytes < (src->mem_size / 2)){ if (netSize <= 0){ heapRecv(Client, 2048); continue; } if (strncmp((char*)netBuffer, "EOF", 3) == 0) break; memcpy(&streamCache[songPointer + processedBytes], netBuffer, netSize); processedBytes = processedBytes + netSize; heapRecv(Client, 2048); } memcpy(src->audiobuf, &streamCache[songPointer], src->mem_size); if (songPointer == 0) songPointer = src->mem_size / 2; else songPointer = 0; src->audio_pointer = src->audio_pointer + src->mem_size; // Changing endianess if Big Endian if (src->big_endian){ u64 i = 0; while (i < src->mem_size){ u8 tmp = src->audiobuf[i]; src->audiobuf[i] = src->audiobuf[i+1]; src->audiobuf[i+1] = tmp; i=i+2; } } } // Check if a block playback is finished u32 curSample = ndspChnGetSamplePos(src->ch); if (src->lastCheck > curSample){ // Prepare next block src->wavebuf = src->wavebuf2; src->wavebuf2 = NULL; } // Update sample position tick src->lastCheck = curSample; } } }