#COMPILE DLL #OPTION VERSION5 ' compile for Windows2000 and/or NT5 #REGISTER ALL #DIM ALL #INCLUDE "C:\b\pb\winapi\Win32api.inc" ' Win32API #INCLUDE "C:\b\pb\winapi\commctrl.inc" ' required for gmt. ' Next we declare all our own constants: #INCLUDE "C:\b\pb\gmt\gmt_kons.bi" ' only integer and string constants can be declared in PB #INCLUDE "C:\b\pb\gmt\gmt_type.bi" ' This declares all our own structures, user defined types #INCLUDE "C:\b\pb\gmt\gmt_lib.bi" ' loads the library DLL, by including its declarations. #INCLUDE "c:\b\pb\gmt\kristof\audexp\AE_kons.bi" #INCLUDE "c:\b\pb\gmt\kristof\audexp\AE_Types.inc" #INCLUDE "c:\b\pb\gmt\gmt_lib.bi" GLOBAL pWbh() AS WAVEHDR PTR ' array of pointers to the the wavebufferheaders in GMT FUNCTION doesitwork EXPORT AS LONG MSGBOX "itdoeswork" END FUNCTION SUB AE_PrepareWaveFunctions (WavHdr() AS WAVEHDR) EXPORT 'publishes pointer to WavHdr() structure to this dll. don't call it too early in gmt!!! ' called in InitGlobals in GMT. ' This way we know the structures as used in GMT in this DLL. ' note that we wrote this in gmt_lib.bas: ' GLOBAL pTrackStat AS AudioTrackStatus PTR ' 05.03.2000 - value initialized in callbacks for waveIN/OUT ' GLOBAL pWbh() AS WAVEHDR PTR ' array of pointers to the the wavebufferheaders in GMT LOCAL i AS LONG REDIM pWbh(0 TO UBOUND(WavHdr)) 'AS GLOBAL WAVEHDR PTR FOR i = 0 TO UBOUND(WavHdr) pWbh(i) = VARPTR(WavHdr(i)) NEXT i ' MSGBOX STR$(pWbh(i)) ' pTrackStat = VARPTR(TrackStatus) END SUB SUB AE_GranulateTrack (BYVAL track AS LONG, BYVAL Env AS DWORD, BYREF Grain AS Graintype) EXPORT ' This procedure splits a track in grains of length = Grainlength 'left channel only!! 'Env 1 = WAS linear fade, not suported anymore 'since we use PTR's in stead of 2D array this becomes more difficult... 'Env 2 = hanning window 'Env 3 = triangle window 'Env 4 w. beta curve LOCAL pGrain AS INTEGER PTR LOCAL pSamp AS INTEGER PTR LOCAL pDest AS INTEGER PTR 'pointer to destination = place in array LOCAL SamCount AS DWORD LOCAL GrainCount AS DWORD LOCAL NrGrains AS DWORD DIM Sh(0 TO Grain.length - 1) AS LOCAL SINGLE MAT Sh() = CON ' sets the whole array to 1 SELECT CASE Env CASE 2 HanningWindow Sh() CASE 3 TriangleWindow Sh() CASE 4 BetaWindow Sh(), 3, 3 END SELECT pGrain = @pWBH(track).lpData '@pWbh(track).lpData 'first in code, last in DLL pDest = Grain.pArr DO WHILE GrainCount < Grain.nr '<, so indeed nr itself is dropeed as we started at 0 pSamp = pGrain DO WHILE SamCount < Grain.Length @pDest = INT(@pSamp * Sh(SamCount)) ' SELECT CASE Env ' CASE 1 ' SELECT CASE SamCount ' 'we do linear fade in / out ' CASE < 240 ' GranAr(GrainCount, SamCount) = GranAr(GrainCount, SamCount) * (SamCount / 240) ' CASE > GrainLength - 240 ' GranAr(GrainCount, SamCount) = GranAr(GrainCount, SamCount) * ((GrainLength - SamCount)/ 240) ' END SELECT ' CASE ELSE ' GranAr(GrainCount, SamCount) = GranAr(GrainCount, SamCount) * Sh(SamCount) ' END SELECT INCR pSamp INCR pSamp 'again doing left channel only INCR pDest 'put everything in one long row INCR pGrain 'if we increase pgrain once here, it precisely in half of the sample at the end = start of next grain for now INCR SamCount LOOP SamCount = %false INCR GrainCount LOOP ' ToLog "AEG end" ' now we have all the grains in GranAr() END SUB FUNCTION GranusynthEx (GSD AS GrainSynthDataType) EXPORT AS LONG'(BYREF GranAr() AS INTEGER, BYREF OverlapFactor() AS SINGLE,BYVAL duration AS DWORD) AS LONG 'based on Granusynth2 'but here overlap() is an array, so the overlap factor changes over time, following linear curves 'between the values in the array 'we don't limit overlapfactor boundaries here. ' overlapfactor < 0.5 - creates electronic artefacts... might be wanted ' overlapfactor: 0.5 - classic used for timestretching ' 1 - no overlapping, grains in succession ' 2 - leaves holes. 'unlike granusynth2, this function 'uses up' the whole array ' duration: duration of the wavesound you want to generate (in ms) ' This function generates two identical 180° out of phase channels (left= -right) ' and returns the tracknumber. LOCAL track AS LONG LOCAL Div AS SINGLE 'divisor if we mix grains LOCAL pTrack AS INTEGER PTR LOCAL pGrainStart AS INTEGER PTR LOCAL MaxpTrack AS DWORD LOCAL GrainId AS SINGLE LOCAL SamCount AS DWORD LOCAL stap AS DWORD LOCAL Pos AS LONG 'position (in bytes!) in wavebuffer that is written (working in samples required unecessary divisions LOCAL MaxPos AS LONG 'maximum of pos LOCAL dum AS SINGLE LOCAL i AS DWORD 'counter 'make sure overlap(x) > 0 FOR i = 0 TO Gsd.lOverl 'LBOUND(OverlapFactor) TO UBOUND(OverlapFactor) IF Gsd.@pOverl[i] <= 0 THEN GSD.@pOverl[i] = .1 END IF NEXT track = GetFreeAudioTrack IF track < %False THEN FUNCTION = -1 EXIT FUNCTION END IF SizeAudioTrack track, GSD.duration pTrack = @pWbh(track).lpData pGrainStart = @pWbh(track).lpData MaxpTrack = @pWbh(track).lpData + @pWbh(track).dwBufferlength - (4* GSD.@pGrain.Length) MaxPos = MaxpTrack - pTrack 'WavHdr(track).dwBufferlength pos = %false DO SamCount = INT(GrainId) * GSD.@pGrain.length DO @pTrack = @pTrack + div * GSD.@pGrain.@pArr[SamCount]'GranAr(GrainCount,SamCount) INCR pTrack @pTrack = @pTrack - div * GSD.@pGrain.@pArr[SamCount] 'GranAr(GrainCount,SamCount) INCR pTrack INCR SamCount LOOP WHILE SamCount < INT(GrainId + 1)* GSD.@pGrain.length 'WHILE SamCount < GrainLength dum = (GSD.lOverl - 1) * Pos/MaxPos IF FIX(dum) < (GSD.lOverl - 1) THEN dum = (1-FRAC(dum)) * GSD.@pOverl[FIX(dum)] + FRAC(dum) * GSD.@pOverl[CEIL(dum)] div = dum stap = GSD.@pGrain.Length * dum ELSE stap = GSD.@pGrain.Length* GSD.@pOverl[GSD.lOverl - 1] Div = GSD.@pOverl[GSD.lOverl - 1] END IF IF div >1 THEN div = 1 SHIFT LEFT Stap, 2 pGrainStart = pGrainStart + Stap pos = pGrainStart - @pWbh(track).lpData pTrack = pGrainStart GrainId = (GSD.@pGrain.nr - 1) * Pos/MaxPos LOOP UNTIL pTrack > MaxpTrack FUNCTION = track END FUNCTION FUNCTION GranuSynthStoch(GSD AS GrainSynthDataType) EXPORT AS LONG 'based on GranuSynth Ex 'lb() and ub() contain lower and upper boundaries in between wich samples are chosen at random 'if corresponing elements fro lb() and ub() are equal, you're sure that that sample is used, 'so you still have the possiblity to move through the array in alinear way, forward as well as backward 'those boundaries move in time, making linear curves between the elements of the arrays 'OverlapFactor also changes in time 'Duration is that of the result LOCAL track AS LONG LOCAL Div AS SINGLE 'divisor if we mix grains LOCAL pTrack AS INTEGER PTR LOCAL pGrainStart AS INTEGER PTR LOCAL MaxpTrack AS DWORD LOCAL GrainId AS SINGLE LOCAL SamCount AS DWORD LOCAL stap AS DWORD LOCAL Pos AS LONG 'position (in bytes!) in wavebuffer that is written (working in samples required unecessary divisions LOCAL MaxPos AS LONG 'maximum of pos LOCAL dum AS SINGLE LOCAL i AS DWORD 'counter LOCAL clb AS DWORD 'current lower boundary LOCAL cub AS DWORD 'make sure overlap(x) > 0 FOR i = 0 TO GSD.lOverl - 1 IF GSD.@pOverl[i] <= 0 THEN GSD.@pOverl[i] = .1 NEXT 'lb(x) and ub(x) shoudn't be bigger then max nr of grains FOR i = 0 TO GSD.lLb IF GSD.@pLb[i] > GSD.@pGrain.nr - 1 THEN GSD.@pLb[i] = GSD.@pGrain.nr - 1 END IF NEXT FOR i = 0 TO GSD.lUb IF GSD.@pUb[i] > GSD.@pGrain.nr - 1 THEN GSD.@pUb[i] = GSD.@pGrain.nr - 1 END IF NEXT track = GetFreeAudioTrack IF track < %False THEN FUNCTION = -1 EXIT FUNCTION END IF SizeAudioTrack track, GSD.duration pTrack = @pWbh(track).lpData pGrainStart = @pWbh(track).lpData MaxpTrack = @pWbh(track).lpData + @pWbh(track).dwBufferlength - (4* GSD.@pGrain.Length) MaxPos = MaxpTrack - pTrack 'WavHdr(track).dwBufferlength pos = %false GrainId = GSD.@pLb[0] DO SamCount = INT(GrainId) * GSD.@pGrain.length DO @pTrack = @pTrack + div * GSD.@pGrain.@pArr[SamCount]'@pSource 'GranAr(GrainId,SamCount) INCR pTrack @pTrack = @pTrack - div * GSD.@pGrain.@pArr[SamCount]'@pSource 'GranAr(GrainId,SamCount) INCR pTrack INCR SamCount LOOP WHILE SamCount < INT(GrainId + 1)* GSD.@pGrain.length dum = (GSD.lOverl - 1) * Pos/MaxPos IF FIX(dum) < (GSD.lOverl-1) THEN dum = (1-FRAC(dum)) * GSD.@pOverl[fix(dum)] + FRAC(dum) * GSD.@pOverl[ceil(dum)]'@pX div = dum stap = GSD.@pGrain.Length * dum ELSE Div = GSD.@pOverl[GSD.lOverl-1]'OverlapFactor(UBOUND(OverlapFactor)) stap = GSD.@pGrain.Length* Div '( OverlapFactor(UBOUND(OverlapFactor)) + RND * deviation - HalfDev ) END IF IF div >1 THEN div = 1 SHIFT LEFT Stap, 2 pGrainStart = pGrainStart + Stap pos = pGrainStart - @pWbh(track).lpData IF pos > MaxPos THEN 'ToLog "GSS Pos > Max" + STR$(Pos) + STR$(MaxPos) FUNCTION = track EXIT FUNCTION END IF pTrack = pGrainStart dum =(GSD.lLb - 1) * Pos/MaxPos 'UBOUND(lb) * Pos/MaxPos IF FIX(dum) < (GSD.lLb - 1) THEN clb = (1-FRAC(dum)) * GSD.@pLb[FIX(dum)] + FRAC(dum) * GSD.@pLb[CEIL(dum)] ELSE clb = GSD.@pLb[GSD.lLb - 1] END IF dum = (GSD.lUb - 1) * Pos/MaxPos 'UBOUND(ub) * Pos/MaxPos IF FIX(dum) < (GSD.lUb - 1) THEN cub = (1-FRAC(dum)) * GSD.@pUb[FIX(dum)] + FRAC(dum) * GSD.@pUb[CEIL(dum)] ELSE cub = GSD.@pUb[GSD.lUb - 1] END IF ' ToLog "GSS pos, maxpos" + STR$(pos) + STR$(MaxPos) GrainId = clb + (cub-clb) * RND '- (cub - clb)/2 '???? LOOP UNTIL pTrack > MaxpTrack FUNCTION = track END FUNCTION