type SINUSOIDAL_WAVE
fundamental as float rem Frequency
theta as float rem Instantaneous angle
delta as float rem Incremental rotation
amplitude as float rem Peak amplitude
endtype
dim signal() as SINUSOIDAL_WAVE
function GenerateSignal16(ptr as dword, numsamples as integer)
local integrator as integer = 0
local i as integer
local j as integer
local wtemp as word
for i = 0 to numsamples - 1
integrator = 0
for j = 0 to array count(signal())
inc integrator, int(sin(wrapvalue(signal(j).theta)) * ...
signal(j).amplitude)
inc signal(j).theta, signal(j).delta
next j
wtemp = integrator
*ptr = wtemp
inc ptr, 2
next i
endfunction
function WritePCMWaveFile(filename as string, wavedata_blk as integer, ...
size as integer)
local i as integer
local j as integer
local k as integer
local s2 as integer
local ptr as dword
ptr = get memblock ptr(wavedata_blk)
s2 = size << 1
if file exist(filename)
delete file filename
endif
open to write 1, filename
write byte 1, asc("R")
write byte 1, asc("I")
write byte 1, asc("F")
write byte 1, asc("F")
write long 1, s2 + 42
write byte 1, asc("W")
write byte 1, asc("A")
write byte 1, asc("V")
write byte 1, asc("E")
write byte 1, asc("f")
write byte 1, asc("m")
write byte 1, asc("t")
write byte 1, asc(" ")
write long 1, 16
write word 1, *ptr
inc ptr, 4
write word 1, *ptr
inc ptr, 4
write long 1, *ptr
inc ptr, 4
write long 1, *ptr
inc ptr, 4
write word 1, *ptr
inc ptr, 4
write word 1, *ptr
inc ptr, 4
write byte 1, asc("d")
write byte 1, asc("a")
write byte 1, asc("t")
write byte 1, asc("a")
write long 1, s2
for k = 0 to size - 1
write word 1, *ptr
inc ptr, 2
next k
close file 1
endfunction
REM Project: siggen1
REM Created: 6/16/2007 5:05:46 PM
REM
REM ***** Main Source File *****
REM Project: binauralBeats
REM Created: 3/9/2007 7:26:52 PM
REM
REM ***** Main Source File *****
REM
#constant MAX_VOLUME = 32767
#constant WAVE_FORMAT_PCM = 1
#constant SIZEOF_WAVEFORMATEX = 18
type WAVEFORMATEX
wFormat as word
nChannels as word
nSamplesPerSec as dword
nAvgBytesPerSec as dword
nBlockAlign as word
wBitsPerSample as word
cbSize as word
endtype
global sound_block as integer
global offset as integer
global waveformatex_f as WAVEFORMATEX
global sample_rate as integer
global sample_size as integer
global num_channels as integer
global data_rate as integer
global left_frequency as float
global right_frequency as float
global thetaL as float
global thetaR as float
global deltaL as float
global deltaR as float
global wLTemp as word
global wRTemp as word
global volume as integer
global fileHandle as integer = 1
volume = MAX_VOLUME
sound_block = 1
sample_rate = 11025
sample_size = 16
num_channels = 2
data_rate = ((sample_size * num_channels) / 8) * sample_rate
left_frequency = 440.0
right_frequency = 440.0
waveformatex_f.wFormat = WAVE_FORMAT_PCM
waveformatex_f.nChannels = 2
waveformatex_f.nSamplesPerSec = 11025
waveformatex_f.nAvgBytesPerSec = 44100
waveformatex_f.nBlockAlign = 4
waveformatex_f.wBitsPerSample = 16
waveformatex_f.cbSize = SIZEOF_WAVEFORMATEX
rem WritePCMWaveFile("test.wav", 0, 0)
rem end
make memblock sound_block, 44100 + 28 rem 2 * samples + size of structure.
offset = 0
rem Make the DBPro version of the waveformatex structure. Note it is all DWORDs.
write memblock dword sound_block, offset, WAVE_FORMAT_PCM rem wFormatTag
inc offset, 4
write memblock dword sound_block, offset, num_channels rem nChannels = STEREO
inc offset, 4
write memblock dword sound_block, offset, sample_rate rem nSamplesPerSec
inc offset, 4
write memblock dword sound_block, offset, data_rate rem nAvgBytesPerSec
inc offset, 4
write memblock dword sound_block, offset, 4 rem nBlockAlign = word
inc offset, 4
write memblock dword sound_block, offset, 16 rem wBitsPerSample = 16
inc offset, 4
write memblock dword sound_block, offset, 0 rem cbSize = 0
inc offset, 4
deltaL = left_frequency * 360.0 / sample_rate
deltaR = right_frequency * 360.0 / sample_rate
thetaL = 0.0
thetaR = 180.0 * deltaR
volume = 16384
for i = 0 to 11024
wLTemp = int(sin(wrapvalue(thetaL)) * volume)
wRTemp = int(sin(wrapvalue(thetaR)) * volume)
write memblock word sound_block, offset, wLTemp
inc offset, 2
write memblock word sound_block, offset, wRTemp
inc offset, 2
inc thetaL, deltaL
inc thetaR, deltaR
next i
if sound exist(1)
delete sound 1
endif
make sound from memblock 1, sound_block
delete memblock sound_block
loop sound 1
wait key
end
function WritePCMWaveFile(filename as string, wavedata_blk as integer, ...
size as integer)
local i as integer
local j as integer
local k as integer
local wavesize as integer = 0
if file exist(filename)
delete file filename
endif
wavesize = 44100 * 1 rem 1 second
open to write 1, filename
write byte 1, asc("R")
write byte 1, asc("I")
write byte 1, asc("F")
write byte 1, asc("F")
write long 1, wavesize + 38
write byte 1, asc("W")
write byte 1, asc("A")
write byte 1, asc("V")
write byte 1, asc("E")
write byte 1, asc("f")
write byte 1, asc("m")
write byte 1, asc("t")
write byte 1, asc(" ")
write long 1, waveformatex_f.cbSize
write word 1, waveformatex_f.wFormat
write word 1, waveformatex_f.nChannels
write long 1, waveformatex_f.nSamplesPerSec
write long 1, waveformatex_f.nAvgBytesPerSec
write word 1, waveformatex_f.nBlockAlign
write word 1, waveformatex_f.wBitsPerSample
write word 1, 0
write byte 1, asc("d")
write byte 1, asc("a")
write byte 1, asc("t")
write byte 1, asc("a")
write long 1, wavesize
deltaL = 28800.0 / 11025.0 rem delta = angular rotation per sample period.
deltaR = 30240.0 / 11025.0
volume = 16384
rem FANCY NAME = 2-channel time domain sinewave generator filter.
thetaL = 0.0 rem theta is the angle at any given instant.
thetaR = 180.0 * deltaR rem signals 180 deg out of phase.
for k = 0 to 11024
wLTemp = int(sin(wrapvalue(thetaL)) * volume)
wRTemp = int(sin(wrapvalue(thetaR)) * volume)
write word 1, wLTemp
write word 1, wRTemp
inc thetaL, deltaL
inc thetaR, deltaR
next k
close file 1
endfunction
REM
REM Project: siggen1
REM Created: 6/16/2007 5:05:46 PM
REM
#constant MAX_VOLUME = 32767
#constant WAVE_FORMAT_PCM = 1
#constant SIZEOF_WAVEFORMATEX = 18
#constant SIZEOF_dbWAVEFORMATEX = 28
type WAVEFORMATEX
wFormat as word
nChannels as word
nSamplesPerSec as dword
nAvgBytesPerSec as dword
nBlockAlign as word
wBitsPerSample as word
cbSize as word
endtype
type SINUSOIDAL_WAVE
fundamental as float rem Frequency
theta as float rem Instantaneous angle
delta as float rem Incremental rotation
amplitude as float rem Peak amplitude
endtype
dim signal() as SINUSOIDAL_WAVE
global sound_block as integer
global offset as integer
global waveformatex_f as WAVEFORMATEX
global sample_rate as integer
global sample_size as integer
global num_channels as integer
global data_rate as integer
global basefreq as float
global thetaL as float
global thetaR as float
global deltaL as float
global deltaR as float
global wLTemp as word
global wRTemp as word
global volume as integer
global fileHandle as integer = 1
volume = MAX_VOLUME
sound_block = 1
sample_rate = 11025
sample_size = 16
num_channels = 1
data_rate = ((sample_size * num_channels) / 8) * sample_rate
waveformatex_f.wFormat = WAVE_FORMAT_PCM
waveformatex_f.nChannels = 1
waveformatex_f.nSamplesPerSec = 11025
waveformatex_f.nAvgBytesPerSec = 22050
waveformatex_f.nBlockAlign = 2
waveformatex_f.wBitsPerSample = 16
waveformatex_f.cbSize = SIZEOF_WAVEFORMATEX
make memblock sound_block, 22050 + SIZEOF_dbWAVEFORMATEX
offset = 0
rem Make the DBPro version of the waveformatex structure. Note it is all DWORDs.
write memblock dword sound_block, offset, WAVE_FORMAT_PCM rem wFormatTag
inc offset, 4
write memblock dword sound_block, offset, num_channels rem nChannels = MONO
inc offset, 4
write memblock dword sound_block, offset, sample_rate rem nSamplesPerSec
inc offset, 4
write memblock dword sound_block, offset, data_rate rem nAvgBytesPerSec
inc offset, 4
write memblock dword sound_block, offset, 2 rem nBlockAlign = word
inc offset, 4
write memblock dword sound_block, offset, 16 rem wBitsPerSample = 16
inc offset, 4
write memblock dword sound_block, offset, 0 rem cbSize = 0
inc offset, 4
remstart
This array is the basis for creating instruments with different resonance
characteristics, as well as for creating polyphonic sounds using them. This
example contains fractional subharmonics, which are important in creating
instruments with cavities, like most woodwinds, and stringed instruments.
Percussion is also like this. Keep in mind that this is only the basic
waveform's shape. As an instrument is played, there are alot of independent
forces acting upon it. That is what I meant about then applying envelope
generation for making individual expressions using the basic wave. At this
point, it might be good to use this code, and put some ADSR into it, the
trouble is that it would not be very flexible. A better method involves
DSP techniques, which I will be elaborating upon in the coming weeks, I
hope. That stuff is easier to implement using DSP functions. This is a DSP
function; its called convolution. There are others, but this one is the
easiest to understand. The way I do it here is a summation of the waves'
amplitudes. Ultimately, it would be nice to have code that matched the
harmonic content in terms of volume ratios by the instrument being
emulated.
The audible click every second is the waves not crossing zero at the right
moment. More well suited code would account for this. DSP techniques are
available for fixing this, too...but we are simply making a periodic wave
here, a real application would not use a static buffer, it would use the
MultiMedia dll in Windows to implement a circular buffer. I will also
demonstrate that, as it is far more useful, just a little more involved to
set up. The plus is that this code will work with that system, too. Also,
it will not matter which version of DBPro it is implemented in, another
plus.
remend
basefreq = 440.0 rem A above middle C on a piano.
remstart
Subharmonics are below the fundamental in frequency, so they are fractional.
(The first subharmonic is 1/2 the fundamental, the next 1/4, and so on.) They
are important to give the sound richness and make it warmer sounding.
remend
empty array signal()
array insert at bottom signal()
signal().fundamental = basefreq / 2 rem [1st subharmonic]
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 12288
array insert at bottom signal()
signal().fundamental = basefreq rem [fundamental]
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 6044
array insert at bottom signal()
signal().fundamental = basefreq * 3 rem 3rd harmonic
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 64
array insert at bottom signal()
signal().fundamental = basefreq * 5 rem 5th harmonic
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 32
array insert at bottom signal()
signal().fundamental = basefreq * 7 rem 7th harmonic
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 8
array insert at bottom signal()
signal().fundamental = basefreq * 9 rem 9th harmonic
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 4
array insert at bottom signal()
signal().fundamental = basefreq * 11 rem 11th harmonic
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 4
array insert at bottom signal()
signal().fundamental = basefreq * 13 rem 13th harmonic
signal().theta = 0.0
signal().delta = (signal().fundamental * 360.0) / (1.0 * sample_rate)
signal().amplitude = 4
waveptr = get memblock ptr(sound_block)
inc waveptr, SIZEOF_dbWAVEFORMATEX
GenerateSignal16(waveptr, sample_rate)
if sound exist(1)
delete sound 1
endif
make sound from memblock 1, sound_block
delete memblock sound_block
loop sound 1
wait key
end
function GenerateSignal16(ptr as dword, numsamples as integer)
local integrator as integer = 0
local i as integer
local j as integer
local wtemp as word
for i = 0 to numsamples - 1
integrator = 0
for j = 0 to array count(signal())
inc integrator, int(sin(wrapvalue(signal(j).theta)) * ...
signal(j).amplitude)
inc signal(j).theta, signal(j).delta
next j
wtemp = integrator
*ptr = wtemp
inc ptr, 2
next i
endfunction
function WritePCMWaveFile(filename as string, wavedata_blk as integer, ...
size as integer)
local i as integer
local j as integer
local k as integer
local wavesize as integer = 0
if file exist(filename)
delete file filename
endif
wavesize = 44100 * 1 rem 1 second
open to write 1, filename
write byte 1, asc("R")
write byte 1, asc("I")
write byte 1, asc("F")
write byte 1, asc("F")
write long 1, wavesize + 38
write byte 1, asc("W")
write byte 1, asc("A")
write byte 1, asc("V")
write byte 1, asc("E")
write byte 1, asc("f")
write byte 1, asc("m")
write byte 1, asc("t")
write byte 1, asc(" ")
write long 1, waveformatex_f.cbSize
write word 1, waveformatex_f.wFormat
write word 1, waveformatex_f.nChannels
write long 1, waveformatex_f.nSamplesPerSec
write long 1, waveformatex_f.nAvgBytesPerSec
write word 1, waveformatex_f.nBlockAlign
write word 1, waveformatex_f.wBitsPerSample
write word 1, 0
write byte 1, asc("d")
write byte 1, asc("a")
write byte 1, asc("t")
write byte 1, asc("a")
write long 1, wavesize
deltaL = 28800.0 / 11025.0 rem delta = angular rotation per sample period.
deltaR = 30240.0 / 11025.0
volume = 16384
rem FANCY NAME = 2-channel time domain sinewave generator filter.
thetaL = 0.0 rem theta is the angle at any given instant.
thetaR = 180.0 * deltaR rem signals 180 deg out of phase.
for k = 0 to 11024
wLTemp = int(sin(wrapvalue(thetaL)) * volume)
wRTemp = int(sin(wrapvalue(thetaR)) * volume)
write word 1, wLTemp
write word 1, wRTemp
inc thetaL, deltaL
inc thetaR, deltaR
next k
close file 1
endfunction