1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
#include "muxer.h"
#include <cstdlib>
#include <sndfile.h>
#include <portaudio.h>
#include <list>
#include <cmath>
#define SAMPLE_RATE (44100)
class Sound {
public:
Sound(const char* filename, float vol);
~Sound();
float* ptr;
unsigned long pos;
unsigned long len;
float vol;
};
struct Muxer {
std::list<Sound> playing;
PaStream* stream;
};
inline void dealWithPaError(PaError err)
{
if (err != paNoError)
{
printf("PortAudio error: %s\n", Pa_GetErrorText(err));
exit(-1);
}
}
int paMuxerCallback(const void*, void* outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void* userData)
{
Muxer* muxer = (Muxer*) userData;
float* out = (float*) outputBuffer;
for (unsigned long i = 0; i<framesPerBuffer; i++)
{
unsigned long curAmount = 0;
*out = 0;
for (auto& sound : muxer->playing)
{
if (sound.pos < sound.len)
{
*out += sound.ptr[sound.pos++] * sound.vol;
}
}
out++;
}
return 0;
}
static Muxer* muxer;
void initMuxer()
{
muxer = new Muxer();
dealWithPaError(Pa_Initialize());
dealWithPaError(Pa_OpenDefaultStream(&(muxer->stream), 0, 1, paFloat32, SAMPLE_RATE, paFramesPerBufferUnspecified, paMuxerCallback, muxer));
dealWithPaError(Pa_StartStream(muxer->stream));
}
void destroyMuxer()
{
dealWithPaError(Pa_AbortStream(muxer->stream));
dealWithPaError(Pa_CloseStream(muxer->stream));
dealWithPaError(Pa_Terminate());
delete muxer;
muxer = 0;
}
void playSound(const char* filename, float vol)
{
// First, clear out any sounds that have finished playing
muxer->playing.remove_if([] (Sound& value) { return value.pos >= value.len; });
// Then, add the new sound
muxer->playing.emplace_back(filename, vol);
}
Sound::Sound(const char* filename, float vol)
{
SF_INFO info;
SNDFILE* file = sf_open(filename, SFM_READ, &info);
if (file == nullptr)
{
printf("LibSndFile error: %s\n", sf_strerror(file));
exit(-1);
}
ptr = (float*) malloc(info.frames * info.channels * sizeof(float));
len = info.frames * info.channels;
pos = 0;
this->vol = vol;
sf_readf_float(file, ptr, info.frames);
sf_close(file);
}
Sound::~Sound()
{
free(ptr);
}
|