Skip to content

Instantly share code, notes, and snippets.

@cemevin
Created November 1, 2011 23:59
Show Gist options
  • Select an option

  • Save cemevin/1332328 to your computer and use it in GitHub Desktop.

Select an option

Save cemevin/1332328 to your computer and use it in GitHub Desktop.
Synthesizer in C++
#include <fstream>
#include <iostream>
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X,Y) ((X) < (Y) ? (Y) : (X))
#define SAMPLE (44100.0)
#define BUFFER_LENGTH ((int)(SAMPLE)*10)
#define C4 (int)(SAMPLE/261.63)
#define D4 (int)(SAMPLE/293.66)
#define E4 (int)(SAMPLE/329.63)
#define F4 (int)(SAMPLE/349.23)
#define G4 (int)(SAMPLE/392.0)
#define A4 (int)(SAMPLE/440.0)
#define B4 (int)(SAMPLE/493.88)
#define C5 C4/2
#define KEY_STATE_PRESSED 0
#define KEY_STATE_RELEASED 1
#define ENVELOPE_STATE_STOP 0
#define ENVELOPE_STATE_ATTACK 1
#define ENVELOPE_STATE_DECAY 2
#define ENVELOPE_STATE_SUSTAIN 3
#define ENVELOPE_STATE_RELEASE 4
using namespace std;
/********** variables **********/
int ENVELOPE_ATTACK = (int)SAMPLE/2;
int ENVELOPE_DECAY = 1;
float ENVELOPE_SUSTAIN = 0.;
int ENVELOPE_RELEASE = 1;
float VOLUME = 0.;
char KEY_STATE = KEY_STATE_RELEASED;
char ENVELOPE_STATE = ENVELOPE_STATE_STOP;
/********** END variables **********/
void setEnvelopeSettings(int attack, int decay, float sustain, int release, float volume = 0., char keystate = KEY_STATE_RELEASED, char envelopestate = ENVELOPE_STATE_STOP){
ENVELOPE_ATTACK = attack;
ENVELOPE_DECAY = decay;
ENVELOPE_SUSTAIN = sustain;
ENVELOPE_RELEASE = release;
VOLUME = volume;
KEY_STATE = keystate;
ENVELOPE_STATE = envelopestate;
}
void osc(int note, unsigned char * buffer, int length){
int note2 = note/2;
for(int i=0; i<length; i++)
{
if(i%note < note2){
buffer[i] = 0xff;
}
else{
buffer[i] = 0x00;
}
}
}
void flush_buffer(ofstream & of, unsigned char * buffer, int length){
for(int j=0;j<length;j++){
of<<(unsigned char)buffer[j];
}
}
float envelope_stop();
float envelope_attack();
float envelope_decay();
float envelope_sustain();
float envelope_release();
float envelope();
int main()
{
unsigned char buffer[BUFFER_LENGTH]; //10 second buffer
int time = 0;
int notes[]={C4,D4,E4,F4,G4,A4,B4,C5,C5,B4,A4,G4,F4,E4,D4,C4};
ofstream of("output1.raw");
/*for(int i=0;i<1;i++){
osc(notes[i], buffer, noteLength);
flush_buffer(of, buffer, noteLength);
}*/
int pressLength = (int)SAMPLE/2;
int releaseLength = 1;
int noteLength = pressLength + releaseLength;
setEnvelopeSettings((int)SAMPLE/2, 1, 0., 1);
//setEnvelopeSettings((int)SAMPLE/4, (int)SAMPLE/4, 0.3, 1);
for(int nott = 0;nott<16;nott++){
osc(notes[nott], buffer, noteLength);
int i;
float env;
KEY_STATE = KEY_STATE_PRESSED;
for(i=0;i<pressLength;i++){ //simulating 2 seconds long key-press
envelope();
buffer[i] = (unsigned char)(buffer[i] * VOLUME);
}
KEY_STATE = KEY_STATE_RELEASED;
for(;i<noteLength;i++){ //simulating key-release
envelope();
buffer[i] = (unsigned char)(buffer[i] * VOLUME);
}
flush_buffer(of, buffer, noteLength);
}
getchar();
of.close();
}
void shiftEnvelopeState(){
ENVELOPE_STATE++;
ENVELOPE_STATE %= 5;
}
void setEnvelopeState(char state){
ENVELOPE_STATE = state;
}
float envelope_stop(){
if(KEY_STATE == KEY_STATE_PRESSED){
shiftEnvelopeState();
envelope_attack();
}
}
float envelope_attack(){
if(KEY_STATE == KEY_STATE_PRESSED){
if(VOLUME == 1.){
shiftEnvelopeState();
//cout<<"shifting from attack to decay"<<endl;
envelope_decay();
}
else{
VOLUME = MIN(1., VOLUME + (1.0)/ENVELOPE_ATTACK);
//cout<<"attack "<<VOLUME<<endl;
}
}
else{
setEnvelopeState(ENVELOPE_STATE_RELEASE);
if(VOLUME == 0.){
shiftEnvelopeState();
}
else{
VOLUME = MAX(0., VOLUME - (1.0)/ENVELOPE_RELEASE);
}
}
}
float envelope_decay(){
if(KEY_STATE == KEY_STATE_PRESSED){
if(VOLUME == ENVELOPE_SUSTAIN){
shiftEnvelopeState();
//cout<<"shifting from decay to sustain"<<endl;
envelope_sustain();
}
else{
VOLUME = MAX(ENVELOPE_SUSTAIN, (VOLUME - (1.0)/ENVELOPE_DECAY));
//cout<<"decay "<<(VOLUME - (1.0)/ENVELOPE_DECAY)<<endl;
}
}
else{
setEnvelopeState(ENVELOPE_STATE_RELEASE);
if(VOLUME == 0.){
shiftEnvelopeState();
}
else{
VOLUME = MAX(0., VOLUME - (1.0)/ENVELOPE_RELEASE);
}
}
}
float envelope_sustain(){
if(KEY_STATE == KEY_STATE_PRESSED){
VOLUME = ENVELOPE_SUSTAIN;
}
else{
setEnvelopeState(ENVELOPE_STATE_RELEASE);
if(VOLUME == 0.){
shiftEnvelopeState();
}
else{
VOLUME = MAX(0., VOLUME - (1.0)/ENVELOPE_RELEASE);
}
}
}
float envelope_release(){
if(KEY_STATE == KEY_STATE_PRESSED){
shiftEnvelopeState();
envelope_stop();
}
else{
if(VOLUME == 0.){
shiftEnvelopeState();
}
else{
VOLUME = MAX(0., VOLUME - (1.0)/ENVELOPE_RELEASE);
}
}
}
float envelope(){
switch(ENVELOPE_STATE){
case ENVELOPE_STATE_STOP:
envelope_stop();
break;
case ENVELOPE_STATE_ATTACK:
envelope_attack();
break;
case ENVELOPE_STATE_DECAY:
envelope_decay();
break;
case ENVELOPE_STATE_SUSTAIN:
envelope_sustain();
break;
case ENVELOPE_STATE_RELEASE:
envelope_release();
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment