ultimatepp/examples/Synth/Core.cpp
cxl 376df036cd .examples
git-svn-id: svn://ultimatepp.org/upp/trunk@12698 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2019-01-22 09:33:28 +00:00

193 lines
4.3 KiB
C++

#include "Synth.h"
#ifdef PLATFORM_POSIX
#include <SDL2/SDL.h>
#else
#include <SDL.h>
#endif
SoundGen app_sch[NUM_CHANNELS]; // to avoid lengthy locking, keep copy under different mutex
SoundGen gen_sch[NUM_CHANNELS]; // this is copied to generator and used to actually generate the sound
INITBLOCK {
for(int i = 0; i < NUM_CHANNELS; i++) // initialize wave_tab
for(int j = 0; j < OPCOUNT; j++) {
app_sch[i].op[j].Comp();
gen_sch[i].op[j].Comp();
}
}
int in_sch_serial;
#if 1
struct AppSoundLock {
AppSoundLock() { SDL_LockAudio(); }
~AppSoundLock() { SDL_UnlockAudio(); }
};
struct GenSoundLock {
GenSoundLock() {}
~GenSoundLock() {}
};
#else
SpinLock s_in_sch_lock;
struct AppSoundLock {
AppSoundLock() { s_in_sch_lock.Enter(); }
~AppSoundLock() { s_in_sch_lock.Leave(); }
};
struct GenSoundLock {
GenSoundLock() { s_in_sch_lock.Enter(); }
~GenSoundLock() { s_in_sch_lock.Leave(); }
};
#endif
void SetChannel(int chi, const Sound& c, int priority, int id)
{
AppSoundLock __;
SoundGen& ch = app_sch[chi];
ch.Start(c);
ch.priority = priority;
ch.serial = ++in_sch_serial;
ch.id = id;
}
void StopChannels(int id)
{
AppSoundLock __;
for(int i = 0; i < NUM_CHANNELS; i++) {
SoundGen& ch = app_sch[i];
if(ch.id == id) {
ch.serial = ++in_sch_serial;
ch.current_volume = app_sch[i].op[0].volume = 0;
}
}
}
void SetChannelVolume(int chi, double volume)
{
AppSoundLock __;
SoundGen& ch = app_sch[chi];
ch.param_serial = ++in_sch_serial;
ch.op[0].volume = pow(10, (volume - 100) / 40);
}
int FindChannel(int priority, int from, double new_volume)
{
new_volume = pow(10, (new_volume - 100) / 40);
AppSoundLock __;
int besti = -1;
int best_priority = INT_MAX;
double best_volume = 100;
for(int i = from; i < NUM_CHANNELS; i++) {
SoundGen& ch = app_sch[i];
// if(ch.current_volume < 0.001) {
// besti = i;
// break;
// }
if(/*ch.priority <= priority &&
(ch.priority < best_priority || ch.priority == best_priority && */ch.current_volume < best_volume) {
besti = i;
// best_priority = ch.priority;
best_volume = ch.current_volume;
}
}
// return besti;
return best_volume < new_volume ? besti : -1;
// DDUMP(best_volume);
// DDUMP(besti);
/* if(besti < 0)
for(int i = from; i < NUM_CHANNELS; i++)
if(app_sch[i].current_volume < 0.01) {
besti = i;
break;
}
return besti;*/
}
extern void Sequencer(int chunk_size);
float global_volume = 1;
void SetGlobalVolume(float vol)
{
AppSoundLock __;
global_volume = vol;
}
void MyAudioCallback(void *, Uint8 *stream, int len)
{
int chunk_size = len / (2 * sizeof(float));
Sequencer(chunk_size);
{
#if 0
RLOG("====================================");
#endif
GenSoundLock __;
for(int i = 0; i < NUM_CHANNELS; i++) {
if(app_sch[i].serial != gen_sch[i].serial)
gen_sch[i] = app_sch[i];
if(app_sch[i].param_serial != gen_sch[i].param_serial) {
gen_sch[i].op[0].volume = app_sch[i].op[0].volume;
gen_sch[i].current_volume = 1;
app_sch[i].param_serial = gen_sch[i].param_serial;
}
#if 0
RLOG(i);
RLOG(gen_sch[i]);
#endif
}
}
float *d = (float *)stream;
memset(d, 0, len);
for(int j = 0; j < NUM_CHANNELS; j++) {
SoundGen& ch = gen_sch[j];
d = (float *)stream;
double v = 0;
for(int i = 0; i < chunk_size; i++) {
float h = ch.Get();
*d++ += ch.lpan * h;
*d++ += ch.rpan * h;
}
}
float *e = (float *)stream + 2 * chunk_size;
for(float *d = (float *)stream; d < e; d++)
*d = clamp(*d * global_volume, -1.0f, 1.0f);
{
GenSoundLock __;
for(int i = 0; i < NUM_CHANNELS; i++) {
app_sch[i].current_volume = gen_sch[i].current_volume;
}
}
}
void InitSoundSynth(bool initsdl)
{
if(initsdl && SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0)
return;
SDL_AudioSpec want;
memset(&want, 0, sizeof(want));
want.freq = 44100;
want.format = AUDIO_F32SYS;
want.channels = 2;
want.samples = CHUNK_SIZE;
want.callback = MyAudioCallback;
if(SDL_OpenAudio(&want, NULL) < 0)
LOG("Failed to open audio: " + (String)SDL_GetError());
SDL_PauseAudio(0);
}
void CloseSoundSynth(bool exitsdl)
{
SDL_CloseAudio();
if(exitsdl)
SDL_Quit();
}