editor/bass-sys/bass24/c/synth/synth.c
2021-01-05 04:17:41 -06:00

157 lines
5 KiB
C

/*
BASS simple synth
Copyright (c) 2001-2017 Un4seen Developments Ltd.
*/
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include "bass.h"
BASS_INFO info;
HSTREAM stream; // the stream
// display error messages
void Error(const char *text)
{
printf("Error(%d): %s\n", BASS_ErrorGetCode(), text);
BASS_Free();
ExitProcess(0);
}
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define KEYS 20
const WORD keys[KEYS] = {
'Q','2','W','3','E','R','5','T','6','Y','7','U',
'I','9','O','0','P',219,187,221
};
#define MAXVOL (0.22*32768)
#define DECAY (MAXVOL/4000)
float vol[KEYS] = { 0 }, pos[KEYS]; // keys' volume and pos
DWORD CALLBACK WriteStream(HSTREAM handle, short *buffer, DWORD length, void *user)
{
int k, c, s;
float omega;
memset(buffer, 0, length);
for (k = 0; k < KEYS; k++) {
if (!vol[k]) continue;
omega = 2 * M_PI * pow(2.0, (k + 3) / 12.0) * 440.0 / info.freq;
for (c = 0; c < length / sizeof(short); c += 2) {
s = buffer[c] + sin(pos[k]) * vol[k];
if (s > 32767) s = 32767;
else if (s < -32768) s = -32768;
buffer[c + 1] = buffer[c] = s; // left and right channels are the same
pos[k] += omega;
if (vol[k] < MAXVOL) {
vol[k] -= DECAY;
if (vol[k] <= 0) { // faded-out
vol[k] = 0;
break;
}
}
}
pos[k] = fmod(pos[k], 2 * M_PI);
}
return length;
}
void main(int argc, char **argv)
{
const char *fxname[9] = { "CHORUS","COMPRESSOR","DISTORTION","ECHO",
"FLANGER","GARGLE","I3DL2REVERB","PARAMEQ","REVERB" };
HFX fx[9] = { 0 }; // effect handles
INPUT_RECORD keyin;
DWORD r, buflen;
printf("BASS Simple Sinewave Synth\n"
"--------------------------\n");
// check the correct BASS was loaded
if (HIWORD(BASS_GetVersion()) != BASSVERSION) {
printf("An incorrect version of BASS.DLL was loaded");
return;
}
BASS_SetConfig(BASS_CONFIG_UPDATEPERIOD, 10); // 10ms update period
// initialize default output device (and measure latency)
if (!BASS_Init(-1, 44100, BASS_DEVICE_LATENCY, 0, NULL))
Error("Can't initialize device");
BASS_SetConfig(BASS_CONFIG_BUFFER, 200); // set default/maximum buffer length to 200ms
BASS_GetInfo(&info);
if (!info.freq) info.freq = 44100; // if the device's output rate is unknown, default to 44100 Hz
stream = BASS_StreamCreate(info.freq, 2, 0, (STREAMPROC*)WriteStream, 0); // create a stream (stereo for effects)
buflen = 10 + info.minbuf + 1; // default buffer size = update period + 'minbuf' + 1ms extra margin
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, buflen / 1000.f); // apply it
BASS_ChannelPlay(stream, FALSE); // start it
printf("device latency: %dms\n", info.latency);
printf("device minbuf: %dms\n", info.minbuf);
printf("ds version: %d (effects %s)\n", info.dsver, info.dsver < 8 ? "disabled" : "enabled");
printf("press these keys to play:\n\n"
" 2 3 5 6 7 9 0 =\n"
" Q W ER T Y UI O P[ ]\n\n"
"press -/+ to de/increase the buffer\n"
"press spacebar to quit\n\n");
if (info.dsver >= 8) // DX8 effects available
printf("press F1-F9 to toggle effects\n\n");
printf("using a %dms buffer\r", buflen);
while (ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &keyin, 1, &r)) {
int key;
if (keyin.EventType != KEY_EVENT) continue;
if (keyin.Event.KeyEvent.wVirtualKeyCode == VK_SPACE) break;
if (keyin.Event.KeyEvent.bKeyDown) {
if (keyin.Event.KeyEvent.wVirtualKeyCode == VK_SUBTRACT
|| keyin.Event.KeyEvent.wVirtualKeyCode == VK_ADD) {
// change the buffer size
if (keyin.Event.KeyEvent.wVirtualKeyCode == VK_SUBTRACT) { // smaller buffer
if (buflen > 11)
buflen--;
else if (!(info.initflags & BASS_DEVICE_DSOUND))
buflen = 0; // no buffer (not available with DirectSound)
} else { // bigger buffer
if (!buflen)
buflen = 11;
else if (buflen < 200)
buflen++;
}
BASS_ChannelSetAttribute(stream, BASS_ATTRIB_BUFFER, buflen / 1000.f); // apply it
if (buflen)
printf("using a %dms buffer\t\t\r", buflen);
else
printf("using no buffer\t\t\r");
}
if (keyin.Event.KeyEvent.wVirtualKeyCode >= VK_F1
&& keyin.Event.KeyEvent.wVirtualKeyCode <= VK_F9) {
r = keyin.Event.KeyEvent.wVirtualKeyCode - VK_F1;
if (fx[r]) {
BASS_ChannelRemoveFX(stream, fx[r]);
fx[r] = 0;
printf("effect %s = OFF\t\t\r", fxname[r]);
} else {
// set the effect, not bothering with parameters (use defaults)
if (fx[r] = BASS_ChannelSetFX(stream, BASS_FX_DX8_CHORUS + r, 0))
printf("effect %s = ON\t\t\r", fxname[r]);
}
}
}
for (key = 0; key < KEYS; key++)
if (keyin.Event.KeyEvent.wVirtualKeyCode == keys[key]) {
if (keyin.Event.KeyEvent.bKeyDown && vol[key] < MAXVOL) {
pos[key] = 0;
vol[key] = MAXVOL + DECAY / 2; // start key (setting "vol" slightly higher than MAXVOL to cover any rounding-down)
} else if (!keyin.Event.KeyEvent.bKeyDown && vol[key])
vol[key] -= DECAY; // trigger key fadeout
break;
}
}
BASS_Free();
}