renderd7/source/sound.cpp

136 lines
3.7 KiB
C++
Raw Permalink Normal View History

2022-07-24 00:55:18 +02:00
#include <renderd7/sound.hpp>
2021-07-23 15:58:16 +02:00
#include <fstream>
2021-07-23 15:58:16 +02:00
#include <string>
#include <cstring>
2021-07-23 15:58:16 +02:00
#include <renderd7/internal_db.hpp>
2021-07-23 15:58:16 +02:00
using std::string;
// Reference: http://yannesposito.com/Scratch/en/blog/2010-10-14-Fun-with-wav/
typedef struct _WavHeader {
2022-11-12 23:19:41 +01:00
char magic[4]; // "RIFF"
u32 totallength; // Total file length, minus 8.
char wavefmt[8]; // Should be "WAVEfmt "
u32 format; // 16 for PCM format
u16 pcm; // 1 for PCM format
u16 channels; // Channels
u32 frequency; // Sampling frequency
u32 bytes_per_second;
u16 bytes_by_capture;
u16 bits_per_sample;
char data[4]; // "data"
u32 bytes_in_data;
2021-07-23 15:58:16 +02:00
} WavHeader;
static_assert(sizeof(WavHeader) == 44, "WavHeader size is not 44 bytes.");
2022-11-12 23:19:41 +01:00
sound::sound(const string &path, int channel, bool toloop) {
if (rd7i_is_ndsp) {
2022-11-12 23:19:41 +01:00
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspSetOutputCount(2); // Num of buffers
// Reading wav file
std::fstream fp(path, std::ios::in | std::ios::binary);
2022-11-12 23:19:41 +01:00
if (!fp.is_open()) {
2022-11-12 23:19:41 +01:00
printf("Could not open the WAV file: %s\n", path.c_str());
return;
}
WavHeader wavHeader;
fp.read(reinterpret_cast<char*>(&wavHeader), sizeof(WavHeader));
size_t read = fp.tellg();
2022-11-12 23:19:41 +01:00
if (read != sizeof(wavHeader)) {
// Short read.
printf("WAV file header is too short: %s\n", path.c_str());
fp.close();
2022-11-12 23:19:41 +01:00
return;
}
// Verify the header.
static const char RIFF_magic[4] = {'R', 'I', 'F', 'F'};
if (memcmp(wavHeader.magic, RIFF_magic, sizeof(wavHeader.magic)) != 0) {
// Incorrect magic number.
printf("Wrong file format.\n");
fp.close();
2022-11-12 23:19:41 +01:00
return;
}
if (wavHeader.totallength == 0 ||
(wavHeader.channels != 1 && wavHeader.channels != 2) ||
(wavHeader.bits_per_sample != 8 && wavHeader.bits_per_sample != 16)) {
// Unsupported WAV file.
printf("Corrupted wav file.\n");
fp.close();
2022-11-12 23:19:41 +01:00
return;
}
// Get the file size.
fp.seekg(0, std::ios::end);
dataSize = fp.tellg();
dataSize -= sizeof(WavHeader);
2022-11-12 23:19:41 +01:00
// Allocating and reading samples
data = static_cast<u8 *>(linearAlloc(dataSize));
fp.seekg(44, std::ios::beg);
fp.read(reinterpret_cast<char*>(data), dataSize);
fp.close();
2022-11-12 23:19:41 +01:00
dataSize /= 2; // FIXME: 16-bit or stereo?
// Find the right format
u16 ndspFormat;
if (wavHeader.bits_per_sample == 8) {
ndspFormat = (wavHeader.channels == 1) ? NDSP_FORMAT_MONO_PCM8
: NDSP_FORMAT_STEREO_PCM8;
} else {
ndspFormat = (wavHeader.channels == 1) ? NDSP_FORMAT_MONO_PCM16
: NDSP_FORMAT_STEREO_PCM16;
}
ndspChnReset(channel);
ndspChnSetInterp(channel, NDSP_INTERP_NONE);
ndspChnSetRate(channel, float(wavHeader.frequency));
ndspChnSetFormat(channel, ndspFormat);
// Create and play a wav buffer
memset(&waveBuf, 0, sizeof(waveBuf));
waveBuf.data_vaddr = reinterpret_cast<u32 *>(data);
waveBuf.nsamples = dataSize / (wavHeader.bits_per_sample >> 3);
waveBuf.looping = toloop;
waveBuf.status = NDSP_WBUF_FREE;
chnl = channel;
}
2021-07-23 15:58:16 +02:00
}
sound::~sound() {
if (rd7i_is_ndsp) {
2022-11-12 23:19:41 +01:00
waveBuf.data_vaddr = 0;
waveBuf.nsamples = 0;
waveBuf.looping = false;
waveBuf.status = 0;
ndspChnWaveBufClear(chnl);
if (data) {
linearFree(data);
}
}
2021-07-23 15:58:16 +02:00
}
void sound::play() {
if (rd7i_is_ndsp) {
2022-11-12 23:19:41 +01:00
if (!data)
return;
DSP_FlushDataCache(data, dataSize);
ndspChnWaveBufAdd(chnl, &waveBuf);
}
2021-07-23 15:58:16 +02:00
}
void sound::stop() {
if (rd7i_is_ndsp) {
2022-11-12 23:19:41 +01:00
if (!data)
return;
ndspChnWaveBufClear(chnl);
}
2021-11-23 16:39:20 +01:00
}