Web: add panning, move mixing to wasm
This commit is contained in:
+128
-43
@@ -12,9 +12,14 @@
|
||||
#define BREAK_FRAME 1
|
||||
#define BREAK_POINT 2
|
||||
|
||||
// Extra properties
|
||||
#define EXT_PIXELS 0
|
||||
#define EXT_SAMPLES 1
|
||||
// Anaglyph colors
|
||||
#define STEREO_CYAN 0x00C6F0
|
||||
#define STEREO_GREEN 0x00B400
|
||||
#define STEREO_MAGENTA 0xC800FF
|
||||
#define STEREO_RED 0xFF0000
|
||||
|
||||
// Element counts
|
||||
#define NUM_SAMPLES (41700 / 50 * 2)
|
||||
|
||||
|
||||
|
||||
@@ -24,9 +29,11 @@
|
||||
typedef struct {
|
||||
int32_t breaks;
|
||||
uint32_t left[256];
|
||||
float panning;
|
||||
uint8_t pixels[384 * 224 * 4];
|
||||
uint32_t right[256];
|
||||
float samples[41700 * 2];
|
||||
float samples[NUM_SAMPLES];
|
||||
float volume;
|
||||
} Ext;
|
||||
|
||||
|
||||
@@ -43,6 +50,36 @@ int wasmOnFrame(VB *sim) {
|
||||
|
||||
/////////////////////////////// Module Exports ////////////////////////////////
|
||||
|
||||
// Specify anaglyph colors
|
||||
EMSCRIPTEN_KEEPALIVE void SetAnaglyph(VB *sim, uint32_t left, uint32_t right) {
|
||||
Ext *ext = (Ext *) vbGetUserData(sim);
|
||||
|
||||
// Erase all RGB values
|
||||
for (int x = 0; x < 256; x++)
|
||||
ext->left[x] = ext->right[x] = 0xFF000000;
|
||||
|
||||
// Process all RGB channels
|
||||
for (int c = 0, shift = 16; c < 3; c++, shift -= 8) {
|
||||
double max; // Magnitude of channel value
|
||||
uint32_t *dest; // Lookup data
|
||||
|
||||
// Select the magnitude and lookup channel
|
||||
dest = ext->left;
|
||||
max = (left >> shift & 0xFF) / 255.0;
|
||||
if (max == 0) {
|
||||
dest = ext->right;
|
||||
max = (right >> shift & 0xFF) / 255.0;
|
||||
if (max == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compute the resulting RGB values
|
||||
for (int x = 0; x < 256; x++)
|
||||
*dest++ |= (uint32_t) (x * max + 0.5) << (16 - shift);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Instantiate a simulation
|
||||
EMSCRIPTEN_KEEPALIVE void* CreateSim() {
|
||||
size_t sizeOfSim = vbSizeOf();
|
||||
@@ -55,8 +92,11 @@ EMSCRIPTEN_KEEPALIVE void* CreateSim() {
|
||||
|
||||
// Configure extra
|
||||
Ext *ext = (Ext *) (pointer + sizeOfSim);
|
||||
ext->breaks = 0;
|
||||
ext->breaks = 0;
|
||||
ext->panning = 0.0f;
|
||||
ext->volume = 1.0f;
|
||||
vbSetUserData(sim, ext);
|
||||
SetAnaglyph(sim, STEREO_RED, STEREO_CYAN);
|
||||
|
||||
// Initialize pixels with opaque black
|
||||
for (unsigned x = 0; x < 384 * 224; x++)
|
||||
@@ -99,6 +139,16 @@ EMSCRIPTEN_KEEPALIVE int Emulate(VB **sims, unsigned count, uint32_t *clocks) {
|
||||
return vbEmulateEx(sims, count, clocks);
|
||||
}
|
||||
|
||||
// Retrieve a sim's pixel pointer
|
||||
EMSCRIPTEN_KEEPALIVE void* GetExtPixels(VB *sim) {
|
||||
return ((Ext *) vbGetUserData(sim))->pixels;
|
||||
}
|
||||
|
||||
// Retrieve a sim's sample pointer
|
||||
EMSCRIPTEN_KEEPALIVE void* GetExtSamples(VB *sim) {
|
||||
return ((Ext *) vbGetUserData(sim))->samples;
|
||||
}
|
||||
|
||||
// Retrieve the break condition flags for a sim
|
||||
EMSCRIPTEN_KEEPALIVE int32_t GetBreaks(VB *sim) {
|
||||
return ((Ext *) vbGetUserData(sim))->breaks;
|
||||
@@ -127,16 +177,6 @@ EMSCRIPTEN_KEEPALIVE void GetDasm(uint32_t *buffer, void *dasm, int count) {
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve an extra property
|
||||
EMSCRIPTEN_KEEPALIVE void* GetExt(VB *sim, int id) {
|
||||
Ext *ext = (Ext *) vbGetUserData(sim);
|
||||
switch (id) {
|
||||
case EXT_PIXELS : return ext->pixels;
|
||||
case EXT_SAMPLES: return ext->samples;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Retrieve anaglyph-tinted pixels from a sim
|
||||
EMSCRIPTEN_KEEPALIVE void GetPixels(VB *sim) {
|
||||
Ext *ext = (Ext *) vbGetUserData(sim);
|
||||
@@ -146,6 +186,71 @@ EMSCRIPTEN_KEEPALIVE void GetPixels(VB *sim) {
|
||||
*(uint32_t *) pixels = ext->left[pixels[0]] | ext->right[pixels[1]];
|
||||
}
|
||||
|
||||
// Mix audio samples for output
|
||||
EMSCRIPTEN_KEEPALIVE void Mix(float *buffer, VB **sims, int count) {
|
||||
|
||||
// Process all sims
|
||||
for (int x = 0; x < count; x++) {
|
||||
Ext *ext = (Ext *) vbGetUserData(sims[x]);
|
||||
float *samples = ext->samples;
|
||||
float v = ext->volume;
|
||||
|
||||
// First sim initializes buffer
|
||||
if (x == 0) {
|
||||
if (ext->panning < 0) {
|
||||
float l = -ext->panning * v;
|
||||
float r = (1.0f + ext->panning) * v;
|
||||
for (unsigned y = 0; y < NUM_SAMPLES; y += 2) {
|
||||
buffer[y ] = samples[y] * v + samples[y + 1] * l;
|
||||
buffer[y + 1] = samples[y + 1] * r;
|
||||
}
|
||||
} else if (ext->panning > 0) {
|
||||
float r = ext->panning * v;
|
||||
float l = (1.0f - ext->panning) * v;
|
||||
for (unsigned y = 0; y < NUM_SAMPLES; y += 2) {
|
||||
buffer[y ] = samples[y] * l;
|
||||
buffer[y + 1] = samples[y + 1] * v + samples[y] * r;
|
||||
}
|
||||
} else {
|
||||
for (unsigned y = 0; y < NUM_SAMPLES; y++)
|
||||
buffer[y] = samples[y] * v;
|
||||
}
|
||||
}
|
||||
|
||||
// Subsequent sims add to buffer
|
||||
else {
|
||||
if (ext->panning < 0) {
|
||||
float l = -ext->panning * v;
|
||||
float r = (1.0f + ext->panning) * v;
|
||||
for (unsigned y = 0; y < NUM_SAMPLES; y += 2) {
|
||||
buffer[y ] += samples[y] * v + samples[y + 1] * l;
|
||||
buffer[y + 1] += samples[y + 1] * r;
|
||||
}
|
||||
} else if (ext->panning > 0) {
|
||||
float r = ext->panning * v;
|
||||
float l = (1.0f - ext->panning) * v;
|
||||
for (unsigned y = 0; y < NUM_SAMPLES; y += 2) {
|
||||
buffer[y ] += samples[y] * l;
|
||||
buffer[y + 1] += samples[y + 1] * v + samples[y] * r;
|
||||
}
|
||||
} else {
|
||||
for (unsigned y = 0; y < NUM_SAMPLES; y++)
|
||||
buffer[y] += samples[y] * v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Clipping
|
||||
for (unsigned y = 0; y < NUM_SAMPLES; y++) {
|
||||
if (buffer[y] < -1.0f)
|
||||
buffer[y] = -1.0f;
|
||||
else if (buffer[y] > +1.0f)
|
||||
buffer[y] = +1.0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Determine the size in bytes of a pointer
|
||||
EMSCRIPTEN_KEEPALIVE int PointerSize() {
|
||||
return sizeof (void *);
|
||||
@@ -156,32 +261,12 @@ EMSCRIPTEN_KEEPALIVE void* Realloc(void *data, size_t size) {
|
||||
return realloc(data, size);
|
||||
}
|
||||
|
||||
// Specify anaglyph colors
|
||||
EMSCRIPTEN_KEEPALIVE void SetAnaglyph(VB *sim, uint32_t left, uint32_t right) {
|
||||
Ext *ext = (Ext *) vbGetUserData(sim);
|
||||
|
||||
// Erase all RGB values
|
||||
for (int x = 0; x < 256; x++)
|
||||
ext->left[x] = ext->right[x] = 0xFF000000;
|
||||
|
||||
// Process all RGB channels
|
||||
for (int c = 0, shift = 16; c < 3; c++, shift -= 8) {
|
||||
double max; // Magnitude of channel value
|
||||
uint32_t *dest; // Lookup data
|
||||
|
||||
// Select the magnitude and lookup channel
|
||||
dest = ext->left;
|
||||
max = (left >> shift & 0xFF) / 255.0;
|
||||
if (max == 0) {
|
||||
dest = ext->right;
|
||||
max = (right >> shift & 0xFF) / 255.0;
|
||||
if (max == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compute the resulting RGB values
|
||||
for (int x = 0; x < 256; x++)
|
||||
*dest++ |= (uint32_t) (x * max + 0.5) << (16 - shift);
|
||||
}
|
||||
|
||||
// Specify audio panning
|
||||
EMSCRIPTEN_KEEPALIVE void SetPanning(VB *sim, float panning) {
|
||||
((Ext *) vbGetUserData(sim))->panning = panning;
|
||||
}
|
||||
|
||||
// Specify audio volume
|
||||
EMSCRIPTEN_KEEPALIVE void SetVolume(VB *sim, float volume) {
|
||||
((Ext *) vbGetUserData(sim))->volume = volume;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user