Actually added support for drumsynth files and added many ds files
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/branches/lmms/stable-0.3@550 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
25
src/lib/drumsynth.LICENSE
Normal file
25
src/lib/drumsynth.LICENSE
Normal file
@@ -0,0 +1,25 @@
|
||||
DrumSynth Original License (MIT):
|
||||
----------------------------------------------------------------
|
||||
|
||||
Copyright (c) 1998-2000 Paul Kellett (mda-vst.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
712
src/lib/drumsynth.cpp
Normal file
712
src/lib/drumsynth.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
// DrumSynth DS file renderer
|
||||
// Copyright (c)1998-2000 Paul Kellett (mda-vst.com)
|
||||
// Licensed under the MIT License. Read drumsynth.LICENSE for details
|
||||
// Version 2.0 (5/10/00)
|
||||
//
|
||||
// Adapted for LMMS 2007 Paul Giblock
|
||||
//
|
||||
|
||||
#include "drumsynth.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include <math.h> //sin(), exp(), etc.
|
||||
#include <stdio.h> //sscanf(), sprintf()
|
||||
#include <stdlib.h> //RAND_MAX
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define WORD __u16
|
||||
#define DWORD __u32
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
|
||||
const int Fs = 44100;
|
||||
const float TwoPi = 6.2831853f;
|
||||
const int MAX = 0;
|
||||
const int ENV = 1;
|
||||
const int PNT = 2;
|
||||
const int dENV = 3;
|
||||
const int NEXTT = 4;
|
||||
|
||||
// Bah, I'll move these into the class once I sepearate DrumsynthFile from DrumSynth
|
||||
// llama
|
||||
float envpts[8][3][32]; //envelope/time-level/point
|
||||
float envData[8][6]; //envelope running status
|
||||
int chkOn[8], sliLev[8]; //section on/off and level
|
||||
float timestretch; //overall time scaling
|
||||
short DD[1200], clippoint;
|
||||
float DF[1200];
|
||||
float phi[1200];
|
||||
|
||||
long wavewords, wavemode=0;
|
||||
float mem_t=1.0f, mem_o=1.0f, mem_n=1.0f, mem_b=1.0f, mem_tune=1.0f, mem_time=1.0f;
|
||||
|
||||
|
||||
int DrumSynth::LongestEnv(void)
|
||||
{
|
||||
long e, eon, p;
|
||||
float l=0.f;
|
||||
|
||||
for(e=1; e<7; e++) //3
|
||||
{
|
||||
eon = e - 1; if(eon>2) eon=eon-1;
|
||||
p = 0;
|
||||
while (envpts[e][0][p + 1] >= 0.f) p++;
|
||||
envData[e][MAX] = envpts[e][0][p] * timestretch;
|
||||
if(chkOn[eon]==1) if(envData[e][MAX]>l) l=envData[e][MAX];
|
||||
}
|
||||
//l *= timestretch;
|
||||
|
||||
return 2400 + (1200 * (int)(l / 1200));
|
||||
}
|
||||
|
||||
|
||||
float DrumSynth::LoudestEnv(void)
|
||||
{
|
||||
float loudest=0.f;
|
||||
int i=0;
|
||||
|
||||
while (i<5) //2
|
||||
{
|
||||
if(chkOn[i]==1) if(sliLev[i]>loudest) loudest=(float)sliLev[i];
|
||||
i++;
|
||||
}
|
||||
return (loudest * loudest);
|
||||
}
|
||||
|
||||
|
||||
void DrumSynth::UpdateEnv(int e, long t)
|
||||
{
|
||||
float endEnv, dT;
|
||||
//0.2's added
|
||||
envData[e][NEXTT] = envpts[e][0][(long)(envData[e][PNT] + 1.f)] * timestretch; //get next point
|
||||
if(envData[e][NEXTT] < 0) envData[e][NEXTT] = 442000 * timestretch; //if end point, hold
|
||||
envData[e][ENV] = envpts[e][1][(long)(envData[e][PNT] + 0.f)] * 0.01f; //this level
|
||||
endEnv = envpts[e][1][(long)(envData[e][PNT] + 1.f)] * 0.01f; //next level
|
||||
dT = envData[e][NEXTT] - (float)t;
|
||||
if(dT < 1.0) dT = 1.0;
|
||||
envData[e][dENV] = (endEnv - envData[e][ENV]) / dT;
|
||||
envData[e][PNT] = envData[e][PNT] + 1.0f;
|
||||
}
|
||||
|
||||
|
||||
void DrumSynth::GetEnv(int env, const char *sec, const char *key, const char *ini)
|
||||
{
|
||||
char en[256], s[8];
|
||||
int i=0, o=0, ep=0;
|
||||
GetPrivateProfileString(sec, key, "0,0 100,0", en, sizeof(en), ini);
|
||||
en[256]=0; //be safe!
|
||||
|
||||
while(en[i]!=0)
|
||||
{
|
||||
if(en[i] == ',')
|
||||
{
|
||||
if(sscanf(s, "%f", &envpts[env][0][ep])==0) envpts[env][0][ep] = 0.f;
|
||||
o=0;
|
||||
}
|
||||
else if(en[i] == ' ')
|
||||
{
|
||||
if(sscanf(s, "%f", &envpts[env][1][ep])==0) envpts[env][1][ep] = 0.f;
|
||||
o=0; ep++;
|
||||
}
|
||||
else { s[o]=en[i]; o++; s[o]=0; }
|
||||
i++;
|
||||
}
|
||||
if(sscanf(s, "%f", &envpts[env][1][ep])==0) envpts[env][1][ep] = 0.f;
|
||||
envpts[env][0][ep + 1] = -1;
|
||||
|
||||
envData[env][MAX] = envpts[env][0][ep];
|
||||
}
|
||||
|
||||
|
||||
float DrumSynth::waveform(float ph, int form)
|
||||
{
|
||||
float w;
|
||||
|
||||
switch (form)
|
||||
{
|
||||
case 0: w = (float)sin(fmod(ph,TwoPi)); break; //sine
|
||||
case 1: w = (float)fabs(2.0f*(float)sin(fmod(0.5f*ph,TwoPi)))-1.f; break; //sine^2
|
||||
case 2: while(ph<TwoPi) ph+=TwoPi;
|
||||
w = 0.6366197f * (float)fmod(ph,TwoPi) - 1.f; //tri
|
||||
if(w>1.f) w=2.f-w; break;
|
||||
case 3: w = ph - TwoPi * (float)(int)(ph / TwoPi); //saw
|
||||
w = (0.3183098f * w) - 1.f; break;
|
||||
default: w = (sin(fmod(ph,TwoPi))>0.0)? 1.f: -1.f; break; //square
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
int DrumSynth::GetPrivateProfileString(const char *sec, const char *key, const char *def, char *buffer, int size, const char *file)
|
||||
{
|
||||
ifstream is;
|
||||
bool inSection = false;
|
||||
char *line;
|
||||
char *k, *b;
|
||||
int len = 0;
|
||||
|
||||
line = (char*)malloc(200);
|
||||
|
||||
is.open (file, ifstream::in);
|
||||
|
||||
while (is.good()) {
|
||||
if (!inSection) {
|
||||
is.ignore( numeric_limits<streamsize>::max(), '[');
|
||||
|
||||
if (!is.eof()) {
|
||||
is.getline(line, 200, ']');
|
||||
if (strcasecmp(line, sec)==0) {
|
||||
inSection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!is.eof()) {
|
||||
is.getline(line, 200);
|
||||
if (line[0] == '[')
|
||||
break;
|
||||
|
||||
k = strtok(line, " \t=");
|
||||
b = strtok(NULL, "\n\r\0");
|
||||
|
||||
if (k != 0 && strcasecmp(k, key)==0) {
|
||||
if (b==0) {
|
||||
len = 0;
|
||||
buffer[0] = 0;
|
||||
}
|
||||
else {
|
||||
k = (char *)(b + strlen(b)-1);
|
||||
while ( (k>=b) && (*k==' ' || *k=='\t') )
|
||||
--k;
|
||||
*(k+1) = '\0';
|
||||
|
||||
len = strlen(b);
|
||||
if (len > size-1) len = size-1;
|
||||
strncpy(buffer, b, len+1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
len = strlen(def);
|
||||
strncpy(buffer, def, size);
|
||||
}
|
||||
|
||||
is.close();
|
||||
free(line);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int DrumSynth::GetPrivateProfileInt(const char *sec, const char *key, int def, const char *file)
|
||||
{
|
||||
char tmp[16];
|
||||
int i=0;
|
||||
|
||||
GetPrivateProfileString(sec, key, "", tmp, sizeof(tmp), file);
|
||||
sscanf(tmp, "%d", &i); if(tmp[0]==0) i=def;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
float DrumSynth::GetPrivateProfileFloat(const char *sec, const char *key, float def, const char *file)
|
||||
{
|
||||
char tmp[16];
|
||||
float f=0.f;
|
||||
|
||||
GetPrivateProfileString(sec, key, "", tmp, sizeof(tmp), file);
|
||||
sscanf(tmp, "%f", &f); if(tmp[0]==0) f=def;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
// Constantly opening and scanning each file for the setting really sucks.
|
||||
// But, the original did this, and we know it works. Will store file into
|
||||
// an associative array or something once we have a datastructure to load in to.
|
||||
// llama
|
||||
|
||||
int DrumSynth::GetDSFileSamples(const char *dsfile, int16_t *&wave, int channels)
|
||||
{
|
||||
//input file
|
||||
char sec[32];
|
||||
char ver[32];
|
||||
char comment[256];
|
||||
char percent[16];
|
||||
int commentLen=0;
|
||||
|
||||
//generation
|
||||
long Length, pos=0, tpos=0, tplus, totmp, t, i, j;
|
||||
float x[3] = {0.f, 0.f, 0.f};
|
||||
float MasterTune, randmax, randmax2;
|
||||
int MainFilter, HighPass;
|
||||
|
||||
long NON, NT, TON, DiON, TDroop=0, DStep;
|
||||
float a, b=0.f, c=0.f, d=0.f, g, TT=0.f, TTT=0.f, TL, NL, F1, F2, Fsync;
|
||||
float TphiStart=0.f, Tphi, TDroopRate, ddF, DAtten, DGain;
|
||||
|
||||
long BON, BON2, BFStep, BFStep2, botmp;
|
||||
float BdF=0.f, BdF2=0.f, BPhi, BPhi2, BF, BF2, BQ, BQ2, BL, BL2;
|
||||
|
||||
long OON, OF1Sync=0, OF2Sync=0, OMode, OW1, OW2;
|
||||
float Ophi1, Ophi2, OF1, OF2, OL, Ot=0 /*PG: init */, OBal1, OBal2, ODrive;
|
||||
float Ocf1, Ocf2, OcF, OcQ, OcA, Oc[6][2]; //overtone cymbal mode
|
||||
float Oc0=0.0f, Oc1=0.0f, Oc2=0.0f;
|
||||
|
||||
float MFfb, MFtmp, MFres, MFin=0.f, MFout=0.f;
|
||||
float DownAve;
|
||||
long DownStart, DownEnd, jj;
|
||||
|
||||
|
||||
if(wavemode==0) //semi-real-time adjustments if working in memory!!
|
||||
{
|
||||
mem_t = 1.0f;
|
||||
mem_o = 1.0f;
|
||||
mem_n = 1.0f;
|
||||
mem_b = 1.0f;
|
||||
mem_tune = 0.0f;
|
||||
mem_time = 1.0f;
|
||||
}
|
||||
|
||||
//try to read version from input file
|
||||
strcpy(sec, "General");
|
||||
GetPrivateProfileString(sec,"Version","",ver,sizeof(ver),dsfile);
|
||||
ver[9]=0;
|
||||
if(strcasecmp(ver, "DrumSynth") != 0) {return 0;} //input fail
|
||||
if(ver[11] != '1' && ver[11] != '2') {return 0;} //version fail
|
||||
|
||||
|
||||
//read master parameters
|
||||
GetPrivateProfileString(sec,"Comment","",comment,sizeof(comment),dsfile);
|
||||
while((comment[commentLen]!=0) && (commentLen<254)) commentLen++;
|
||||
if(commentLen==0) { comment[0]=32; comment[1]=0; commentLen=1;}
|
||||
comment[commentLen+1]=0; commentLen++;
|
||||
if((commentLen % 2)==1) commentLen++;
|
||||
|
||||
timestretch = .01f * mem_time * GetPrivateProfileFloat(sec,"Stretch",100.0,dsfile);
|
||||
if(timestretch<0.2f) timestretch=0.2f;
|
||||
if(timestretch>10.f) timestretch=10.f;
|
||||
|
||||
DGain = 1.0f; //leave this here!
|
||||
DGain = (float)powf(10.0, 0.05 * GetPrivateProfileFloat(sec,"Level",0,dsfile));
|
||||
|
||||
MasterTune = GetPrivateProfileFloat(sec,"Tuning",0.0,dsfile);
|
||||
MasterTune = (float)powf(1.0594631f, MasterTune + mem_tune);
|
||||
MainFilter = 2 * GetPrivateProfileInt(sec,"Filter",0,dsfile);
|
||||
MFres = 0.0101f * GetPrivateProfileFloat(sec,"Resonance",0.0,dsfile);
|
||||
MFres = (float)powf(MFres, 0.5f);
|
||||
|
||||
HighPass = GetPrivateProfileInt(sec,"HighPass",0,dsfile);
|
||||
GetEnv(7, sec, "FilterEnv", dsfile);
|
||||
|
||||
|
||||
//read noise parameters
|
||||
strcpy(sec, "Noise");
|
||||
chkOn[1] = GetPrivateProfileInt(sec,"On",0,dsfile);
|
||||
sliLev[1] = GetPrivateProfileInt(sec,"Level",0,dsfile);
|
||||
NT = GetPrivateProfileInt(sec,"Slope",0,dsfile);
|
||||
GetEnv(2, sec, "Envelope", dsfile);
|
||||
NON = chkOn[1];
|
||||
NL = (float)(sliLev[1] * sliLev[1]) * mem_n;
|
||||
if(NT<0)
|
||||
{ a = 1.f + (NT / 105.f); d = -NT / 105.f;
|
||||
g = (1.f + 0.0005f * NT * NT) * NL; }
|
||||
else
|
||||
{ a = 1.f; b = -NT / 50.f; c = (float)fabs((float)NT) / 100.f; g = NL; }
|
||||
|
||||
//if(GetPrivateProfileInt(sec,"FixedSeq",0,dsfile)!=0)
|
||||
srand(1); //fixed random sequence
|
||||
|
||||
//read tone parameters
|
||||
strcpy(sec, "Tone");
|
||||
chkOn[0] = GetPrivateProfileInt(sec,"On",0,dsfile); TON = chkOn[0];
|
||||
sliLev[0] = GetPrivateProfileInt(sec,"Level",128,dsfile);
|
||||
TL = (float)(sliLev[0] * sliLev[0]) * mem_t;
|
||||
GetEnv(1, sec, "Envelope", dsfile);
|
||||
F1 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F1",200.0,dsfile) / Fs;
|
||||
if(fabs(F1)<0.001f) F1=0.001f; //to prevent overtone ratio div0
|
||||
F2 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F2",120.0,dsfile) / Fs;
|
||||
Fsync = F2;
|
||||
TDroopRate = GetPrivateProfileFloat(sec,"Droop",0.f,dsfile);
|
||||
if(TDroopRate>0.f)
|
||||
{
|
||||
TDroopRate = (float)powf(10.0f, (TDroopRate - 20.0f) / 30.0f);
|
||||
TDroopRate = TDroopRate * -4.f / envData[1][MAX];
|
||||
TDroop = 1;
|
||||
F2 = F1+((F2-F1)/(1.f-(float)exp(TDroopRate * envData[1][MAX])));
|
||||
ddF = F1 - F2;
|
||||
}
|
||||
else ddF = F2-F1;
|
||||
|
||||
Tphi = GetPrivateProfileFloat(sec,"Phase",90.f,dsfile) / 57.29578f; //degrees>radians
|
||||
|
||||
//read overtone parameters
|
||||
strcpy(sec, "Overtones");
|
||||
chkOn[2] = GetPrivateProfileInt(sec,"On",0,dsfile); OON = chkOn[2];
|
||||
sliLev[2] = GetPrivateProfileInt(sec,"Level",128,dsfile);
|
||||
OL = (float)(sliLev[2] * sliLev[2]) * mem_o;
|
||||
GetEnv(3, sec, "Envelope1", dsfile);
|
||||
GetEnv(4, sec, "Envelope2", dsfile);
|
||||
OMode = GetPrivateProfileInt(sec,"Method",2,dsfile);
|
||||
OF1 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F1",200.0,dsfile) / Fs;
|
||||
OF2 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F2",120.0,dsfile) / Fs;
|
||||
OW1 = GetPrivateProfileInt(sec,"Wave1",0,dsfile);
|
||||
OW2 = GetPrivateProfileInt(sec,"Wave2",0,dsfile);
|
||||
OBal2 = (float)GetPrivateProfileInt(sec,"Param",50,dsfile);
|
||||
ODrive = (float)powf(OBal2, 3.0f) / (float)powf(50.0f, 3.0f);
|
||||
OBal2 *= 0.01f;
|
||||
OBal1 = 1.f - OBal2;
|
||||
Ophi1 = Tphi;
|
||||
Ophi2 = Tphi;
|
||||
if(MainFilter==0)
|
||||
MainFilter = GetPrivateProfileInt(sec,"Filter",0,dsfile);
|
||||
if((GetPrivateProfileInt(sec,"Track1",0,dsfile)==1) && (TON==1))
|
||||
{ OF1Sync = 1; OF1 = OF1 / F1; }
|
||||
if((GetPrivateProfileInt(sec,"Track2",0,dsfile)==1) && (TON==1))
|
||||
{ OF2Sync = 1; OF2 = OF2 / F1; }
|
||||
|
||||
OcA = 0.28f + OBal1 * OBal1; //overtone cymbal mode
|
||||
OcQ = OcA * OcA;
|
||||
OcF = (1.8f - 0.7f * OcQ) * 0.92f; //multiply by env 2
|
||||
OcA *= 1.0f + 4.0f * OBal1; //level is a compromise!
|
||||
Ocf1 = TwoPi / OF1;
|
||||
Ocf2 = TwoPi / OF2;
|
||||
for(i=0; i<6; i++) Oc[i][0] = Oc[i][1] = Ocf1 + (Ocf2 - Ocf1) * 0.2f * (float)i;
|
||||
|
||||
//read noise band parameters
|
||||
strcpy(sec, "NoiseBand");
|
||||
chkOn[3] = GetPrivateProfileInt(sec,"On",0,dsfile); BON = chkOn[3];
|
||||
sliLev[3] = GetPrivateProfileInt(sec,"Level",128,dsfile);
|
||||
BL = (float)(sliLev[3] * sliLev[3]) * mem_b;
|
||||
BF = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F",1000.0,dsfile) / Fs;
|
||||
BPhi = TwoPi / 8.f;
|
||||
GetEnv(5, sec, "Envelope", dsfile);
|
||||
BFStep = GetPrivateProfileInt(sec,"dF",50,dsfile);
|
||||
BQ = (float)BFStep;
|
||||
BQ = BQ * BQ / (10000.f-6600.f*((float)sqrt(BF)-0.19f));
|
||||
BFStep = 1 + (int)((40.f - (BFStep / 2.5f)) / (BQ + 1.f + (1.f * BF)));
|
||||
|
||||
strcpy(sec, "NoiseBand2");
|
||||
chkOn[4] = GetPrivateProfileInt(sec,"On",0,dsfile); BON2 = chkOn[4];
|
||||
sliLev[4] = GetPrivateProfileInt(sec,"Level",128,dsfile);
|
||||
BL2 = (float)(sliLev[4] * sliLev[4]) * mem_b;
|
||||
BF2 = MasterTune * TwoPi * GetPrivateProfileFloat(sec,"F",1000.0,dsfile) / Fs;
|
||||
BPhi2 = TwoPi / 8.f;
|
||||
GetEnv(6, sec, "Envelope", dsfile);
|
||||
BFStep2 = GetPrivateProfileInt(sec,"dF",50,dsfile);
|
||||
BQ2 = (float)BFStep2;
|
||||
BQ2 = BQ2 * BQ2 / (10000.f-6600.f*((float)sqrt(BF2)-0.19f));
|
||||
BFStep2 = 1 + (int)((40 - (BFStep2 / 2.5)) / (BQ2 + 1 + (1 * BF2)));
|
||||
|
||||
//read distortion parameters
|
||||
strcpy(sec, "Distortion");
|
||||
chkOn[5] = GetPrivateProfileInt(sec,"On",0,dsfile); DiON = chkOn[5];
|
||||
DStep = 1 + GetPrivateProfileInt(sec,"Rate",0,dsfile);
|
||||
if(DStep==7) DStep=20; if(DStep==6) DStep=10; if(DStep==5) DStep=8;
|
||||
|
||||
clippoint = 32700;
|
||||
DAtten = 1.0f;
|
||||
|
||||
if(DiON==1)
|
||||
{
|
||||
DAtten = DGain * (short)LoudestEnv();
|
||||
if(DAtten>32700) clippoint=32700; else clippoint=(short)DAtten;
|
||||
DAtten = (float)powf(2.0, 2.0 * GetPrivateProfileInt(sec,"Bits",0,dsfile));
|
||||
DGain = DAtten * DGain * (float)powf(10.0, 0.05 * GetPrivateProfileInt(sec,"Clipping",0,dsfile));
|
||||
}
|
||||
|
||||
//prepare envelopes
|
||||
randmax = 1.f / RAND_MAX; randmax2 = 2.f * randmax;
|
||||
for (i=1;i<8;i++) { envData[i][NEXTT]=0; envData[i][PNT]=0; }
|
||||
Length = LongestEnv();
|
||||
|
||||
//allocate the buffer
|
||||
//if(wave!=NULL) free(wave);
|
||||
//wave = new int16_t[channels * (Length + 1280)]; //wave memory buffer
|
||||
wave = new int16_t[channels * Length]; //wave memory buffer
|
||||
if(wave==NULL) {return 0;}
|
||||
wavewords = 0;
|
||||
|
||||
/*
|
||||
if(wavemode==0)
|
||||
{
|
||||
//open output file
|
||||
fp = fopen(wavfile, "wb");
|
||||
if(!fp) {return 3;} //output fail
|
||||
|
||||
//set up INFO chunk
|
||||
WI.list = 0x5453494C;
|
||||
WI.listLength = 36 + commentLen;
|
||||
WI.info = 0x4F464E49;
|
||||
WI.isft = 0x54465349;
|
||||
WI.isftLength = 16;
|
||||
strcpy(WI.software, "DrumSynth v2.0 "); WI.software[15]=0;
|
||||
WI.icmt = 0x544D4349;
|
||||
WI.icmtLength = commentLen;
|
||||
|
||||
//write WAV header
|
||||
WH.riff = 0x46464952;
|
||||
WH.riffLength = 36 + (2 * Length) + 44 + commentLen;
|
||||
WH.wave = 0x45564157;
|
||||
WH.fmt = 0x20746D66;
|
||||
WH.waveLength = 16;
|
||||
WH.wFormatTag = WAVE_FORMAT_PCM;
|
||||
WH.nChannels = 1;
|
||||
WH.nSamplesPerSec = Fs;
|
||||
WH.nAvgBytesPerSec = 2 * Fs;
|
||||
WH.nBlockAlign = 2;
|
||||
WH.wBitsPerSample = 16;
|
||||
WH.data = 0x61746164;
|
||||
WH.dataLength = 2 * Length;
|
||||
fwrite(&WH, 1, 44, fp);
|
||||
}
|
||||
*/
|
||||
|
||||
//generate
|
||||
tpos = 0;
|
||||
while(tpos<Length)
|
||||
{
|
||||
tplus = tpos + 1199;
|
||||
|
||||
if(NON==1) //noise
|
||||
{
|
||||
for(t=tpos; t<=tplus; t++)
|
||||
{
|
||||
if(t < envData[2][NEXTT]) envData[2][ENV] = envData[2][ENV] + envData[2][dENV];
|
||||
else UpdateEnv(2, t);
|
||||
x[2] = x[1];
|
||||
x[1] = x[0];
|
||||
x[0] = (randmax2 * (float)rand()) - 1.f;
|
||||
TT = a * x[0] + b * x[1] + c * x[2] + d * TT;
|
||||
DF[t - tpos] = TT * g * envData[2][ENV];
|
||||
}
|
||||
if(t>=envData[2][MAX]) NON=0;
|
||||
}
|
||||
else {
|
||||
for(j=0; j<1200; j++) DF[j]=0.f;
|
||||
}
|
||||
|
||||
if(TON==1) //tone
|
||||
{
|
||||
TphiStart = Tphi;
|
||||
if(TDroop==1)
|
||||
{
|
||||
for(t=tpos; t<=tplus; t++)
|
||||
phi[t - tpos] = F2 + (ddF * (float)exp(t * TDroopRate));
|
||||
}
|
||||
else
|
||||
{
|
||||
for(t=tpos; t<=tplus; t++)
|
||||
phi[t - tpos] = F1 + (t / envData[1][MAX]) * ddF;
|
||||
}
|
||||
for(t=tpos; t<=tplus; t++)
|
||||
{
|
||||
totmp = t - tpos;
|
||||
if(t < envData[1][NEXTT])
|
||||
envData[1][ENV] = envData[1][ENV] + envData[1][dENV];
|
||||
else UpdateEnv(1, t);
|
||||
Tphi = Tphi + phi[totmp];
|
||||
DF[totmp] += TL * envData[1][ENV] * (float)sin(fmod(Tphi,TwoPi));//overflow?
|
||||
}
|
||||
if(t>=envData[1][MAX]) TON=0;
|
||||
}
|
||||
else for(j=0; j<1200; j++) phi[j]=F2; //for overtone sync
|
||||
|
||||
if(BON==1) //noise band 1
|
||||
{
|
||||
for(t=tpos; t<=tplus; t++)
|
||||
{
|
||||
if(t < envData[5][NEXTT])
|
||||
envData[5][ENV] = envData[5][ENV] + envData[5][dENV];
|
||||
else UpdateEnv(5, t);
|
||||
if((t % BFStep) == 0) BdF = randmax * (float)rand() - 0.5f;
|
||||
BPhi = BPhi + BF + BQ * BdF;
|
||||
botmp = t - tpos;
|
||||
DF[botmp] = DF[botmp] + (float)cos(fmod(BPhi,TwoPi)) * envData[5][ENV] * BL;
|
||||
}
|
||||
if(t>=envData[5][MAX]) BON=0;
|
||||
}
|
||||
|
||||
if(BON2==1) //noise band 2
|
||||
{
|
||||
for(t=tpos; t<=tplus; t++)
|
||||
{
|
||||
if(t < envData[6][NEXTT])
|
||||
envData[6][ENV] = envData[6][ENV] + envData[6][dENV];
|
||||
else UpdateEnv(6, t);
|
||||
if((t % BFStep2) == 0) BdF2 = randmax * (float)rand() - 0.5f;
|
||||
BPhi2 = BPhi2 + BF2 + BQ2 * BdF2;
|
||||
botmp = t - tpos;
|
||||
DF[botmp] = DF[botmp] + (float)cos(fmod(BPhi2,TwoPi)) * envData[6][ENV] * BL2;
|
||||
}
|
||||
if(t>=envData[6][MAX]) BON2=0;
|
||||
}
|
||||
|
||||
|
||||
for (t=tpos; t<=tplus; t++)
|
||||
{
|
||||
if(OON==1) //overtones
|
||||
{
|
||||
if(t<envData[3][NEXTT])
|
||||
envData[3][ENV] = envData[3][ENV] + envData[3][dENV];
|
||||
else
|
||||
{
|
||||
if(t>=envData[3][MAX]) //wait for OT2
|
||||
{
|
||||
envData[3][ENV] = 0;
|
||||
envData[3][dENV] = 0;
|
||||
envData[3][NEXTT] = 999999;
|
||||
}
|
||||
else UpdateEnv(3, t);
|
||||
}
|
||||
//
|
||||
if(t<envData[4][NEXTT])
|
||||
envData[4][ENV] = envData[4][ENV] + envData[4][dENV];
|
||||
else
|
||||
{
|
||||
if(t>=envData[4][MAX]) //wait for OT1
|
||||
{
|
||||
envData[4][ENV] = 0;
|
||||
envData[4][dENV] = 0;
|
||||
envData[4][NEXTT] = 999999;
|
||||
}
|
||||
else UpdateEnv(4, t);
|
||||
}
|
||||
//
|
||||
TphiStart = TphiStart + phi[t - tpos];
|
||||
if(OF1Sync==1) Ophi1 = TphiStart * OF1; else Ophi1 = Ophi1 + OF1;
|
||||
if(OF2Sync==1) Ophi2 = TphiStart * OF2; else Ophi2 = Ophi2 + OF2;
|
||||
Ot=0.0f;
|
||||
switch (OMode)
|
||||
{
|
||||
case 0: //add
|
||||
Ot = OBal1 * envData[3][ENV] * waveform(Ophi1, OW1);
|
||||
Ot = OL * (Ot + OBal2 * envData[4][ENV] * waveform(Ophi2, OW2));
|
||||
break;
|
||||
|
||||
case 1: //FM
|
||||
Ot = ODrive * envData[4][ENV] * waveform(Ophi2, OW2);
|
||||
Ot = OL * envData[3][ENV] * waveform(Ophi1 + Ot, OW1);
|
||||
break;
|
||||
|
||||
case 2: //RM
|
||||
Ot = (1 - ODrive / 8) + (((ODrive / 8) * envData[4][ENV]) * waveform(Ophi2, OW2));
|
||||
Ot = OL * envData[3][ENV] * waveform(Ophi1, OW1) * Ot;
|
||||
break;
|
||||
|
||||
case 3: //808 Cymbal
|
||||
for(j=0; j<6; j++)
|
||||
{
|
||||
Oc[j][0] += 1.0f;
|
||||
|
||||
if(Oc[j][0]>Oc[j][1])
|
||||
{
|
||||
Oc[j][0] -= Oc[j][1];
|
||||
Ot = OL * envData[3][ENV];
|
||||
}
|
||||
}
|
||||
Ocf1 = envData[4][ENV] * OcF; //filter freq
|
||||
Oc0 += Ocf1 * Oc1;
|
||||
Oc1 += Ocf1 * (Ot + Oc2 - OcQ * Oc1 - Oc0); //bpf
|
||||
Oc2 = Ot;
|
||||
Ot = Oc1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(MainFilter==1) //filter overtones
|
||||
{
|
||||
if(t<envData[7][NEXTT])
|
||||
envData[7][ENV] = envData[7][ENV] + envData[7][dENV];
|
||||
else UpdateEnv(7, t);
|
||||
|
||||
MFtmp = envData[7][ENV];
|
||||
if(MFtmp >0.2f)
|
||||
MFfb = 1.001f - (float)powf(10.0f, MFtmp - 1);
|
||||
else
|
||||
MFfb = 0.999f - 0.7824f * MFtmp;
|
||||
|
||||
MFtmp = Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout);
|
||||
MFin = MFfb * (MFin - MFtmp) + MFtmp;
|
||||
MFout = MFfb * (MFout - MFin) + MFin;
|
||||
|
||||
DF[t - tpos] = DF[t - tpos] + (MFout - (HighPass * Ot));
|
||||
}
|
||||
else if(MainFilter==2) //filter all
|
||||
{
|
||||
if(t<envData[7][NEXTT])
|
||||
envData[7][ENV] = envData[7][ENV] + envData[7][dENV];
|
||||
else UpdateEnv(7, t);
|
||||
|
||||
MFtmp = envData[7][ENV];
|
||||
if(MFtmp >0.2f)
|
||||
MFfb = 1.001f - (float)powf(10.0f, MFtmp - 1);
|
||||
else
|
||||
MFfb = 0.999f - 0.7824f * MFtmp;
|
||||
|
||||
MFtmp = DF[t - tpos] + Ot + MFres * (1.f + (1.f/MFfb)) * (MFin - MFout);
|
||||
MFin = MFfb * (MFin - MFtmp) + MFtmp;
|
||||
MFout = MFfb * (MFout - MFin) + MFin;
|
||||
|
||||
DF[t - tpos] = MFout - (HighPass * (DF[t - tpos] + Ot));
|
||||
}
|
||||
// PG: Ot is uninitialized
|
||||
else DF[t - tpos] = DF[t - tpos] + Ot; //no filter
|
||||
}
|
||||
|
||||
if(DiON==1) //bit resolution
|
||||
{
|
||||
for(j=0; j<1200; j++)
|
||||
DF[j] = DGain * (int)(DF[j] / DAtten);
|
||||
|
||||
for(j=0; j<1200; j+=DStep) //downsampling
|
||||
{
|
||||
DownAve = 0;
|
||||
DownStart = j;
|
||||
DownEnd = j + DStep - 1;
|
||||
for(jj = DownStart; jj<=DownEnd; jj++)
|
||||
DownAve = DownAve + DF[jj];
|
||||
DownAve = DownAve / DStep;
|
||||
for(jj = DownStart; jj<=DownEnd; jj++)
|
||||
DF[jj] = DownAve;
|
||||
}
|
||||
}
|
||||
else for(j=0; j<1200; j++) DF[j] *= DGain;
|
||||
|
||||
for(j = 0; j<1200; j++) //clipping + output
|
||||
{
|
||||
if(DF[j] > clippoint)
|
||||
wave[wavewords++] = clippoint;
|
||||
else if(DF[j] < -clippoint)
|
||||
wave[wavewords++] = -clippoint;
|
||||
else
|
||||
wave[wavewords++] = (short)DF[j];
|
||||
|
||||
for (int c = 1; c < channels; c++) {
|
||||
wave[wavewords] = wave[wavewords-1];
|
||||
wavewords++;
|
||||
}
|
||||
}
|
||||
|
||||
tpos = tpos + 1200;
|
||||
}
|
||||
|
||||
/*
|
||||
if(wavemode==0)
|
||||
{
|
||||
fwrite(wave, 2, Length, fp); //write data
|
||||
fwrite(&WI, 1, 44, fp); //write INFO chunk
|
||||
fwrite(&comment, 1, commentLen, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
wavemode = 0; //force compatibility!!
|
||||
*/
|
||||
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user