Prof.Dr.Godfried-Willem RAES
<GMT> Library Reference Manual: Module 8: AUDIO related procedures and functions
CHAPTER 8: GMT_AUDIO
Since our release version 4.20, this module went through an almost complete rewrite. Thus we changed most of the audio related functions. Not only the functions became easier to use, but also they are now quite a bit more flexible.
Internally the GMT_Audio support makes use of a maximum of 16 audio channels (tracks). Each channel can be configured for input or output (recording / playback) and makes use of an individual Waveheader structure, residing in the global array WavHdr(0 TO 15). The sample data are stored in 16 individual dynamic global dword arrays AudioTrack0() to AudioTrackF() residing in gmt_lib.dll. If the sum of data in these tracks exceeds the memory of your PC, you may encounter serious problems. GMT does not check for this condition. Be carefull and warned. As yet, continuous playback (as well as continous recording) of these mixed 16 tracks is only possible on reasonably fast PC's. Slower PC's may suffer from glitches. We are working on this problem...
The declarations for all audio related procedures and functions residing in the library g_lib.dll and g_wave.dll can we found in g_lib.bi and g_wave.dll. This file has to be included in your source to get access to the library functions. The source code for the functions explained in this chapter is in the following files:
g_wave.inc & g_wave.bi contains only audio related tasks that can be integrated in the GMT context. Please download the zip files with the complete source code. Once unzipped, these files will be found on your pc. Scanning through the source code will likely clarify questions that we left -by lack of time and collaborators- unanswered in this brief reference guide. To fully understand the source code it is mandatory to have access to the MSDN documentation for the Win32api. (We use the documentation packed with Visual Studio 6.0 from Microsoft, but now it is also available online). Also some understanding of digital audio processing comes in handy. Note that some functions and procedures build on functions and procedures included in out math library. (modules g_math.inc, g_math.bi)
Since version 5.00 we have added support for real time granular synthesis in this function library. Demos are available on request. Also the mci functions for CD access have been changed as we placed them in the library. FFT and DFT function have been revised since version 5.46.
Procedures for handling audio I/O in <GMT> using the Win32Api
List of functions and procedures:
Audio/Wave related procedures and functions:
all simple numeric parameters are passed by value (unless explicitly noted otherwize). Structures (types), complete arrays and strings always by reference.
callback procedures:
modulation functions and procedures:
Wave generators and oscillators:
- GenerateFMdiadWave(f1!,f2!,level!,pan!,d as dword) AS LONG
- GenerateHarmWave(H AS HarmType,pan?,d as dword) AS LONG
- GenerateSineWave(Note?,Velo?,Pan?,d as dword) AS LONG
CD-Related procedures and functions: (code module g_mci.*)
Windows Mixer related functions: (module g_wmix.inc)
Users & Reference guide
1. Audio-related functions and procedures
CALLBACKFUNCTIONS:
This function is the callback for all mci procedures and command. It is coupled to the hidden window created with MakeMCIWindow(). Users do not have to call this functions nor interfere with it in any respect.
Callback procedure for wave input (audiorecording). This procedure sets and reads flags in the Audio structure. It takes care of unpreparing the wave input waveheader, saving samples to disk, playing audioinput as a delayline etc...
Callback procedure for wave output (playing).
Normally users do not have to call any of these functions in their own code, unless they want to automate the setup. The price for doing so however, is that the code becomes very dependent on the organisation of a particular pc and its hardware.
Initialization and Internal functions:
This procedure makes an invisible window just used to implement the required callback window handle for MCI deviced under Win32. It is called whenever an MCI device is opened or selected in the opening menu.
SetMCI (BYREF MCIiD AS MCIdevicetype, BYREF AudioCD AS AudioCDtype)
This procedure is called by GMT on initialisation of MCI devices. It publishes essential pointers to the dll library such that it can access your mci devices and make them functional. If working in the GMT context the user does not need to call this procedure.
SUB ReportError (id AS INTEGER)
Allerts for errors with wave I/O functions and procedures. This procedure is part of the DLL and should not be called on its own.
SUB ReportMCIError (BYVAL hWnd AS LONG, dwError AS LONG)
Allerts for errors with MCI procedures. Used internally. This procedure is part of the DLL.
SUB CloseMCIDevice (BYVAL hWnd AS LONG, BYVAL devID AS LONG)
Closes an MCI device and invalidates its handle, ID. Releases the driver. This procedure is part of the DLL.
Returns the available devices on your PC that can be used for waveinput. This function is called internally during setup.
GetAvailableWaveOutputDevs$ ()
Returns the available devices on your PC that can be used for waveplaying. This function is called internally during setup.
GetWaveInPorts (mp() AS STRING)
Returns the available devices on your PC that can be used for waveinput. This function is called internally during setup.
GetWaveOutPorts(mp() as STRING)
Returns the available devices on your PC that can be used for waveplaying. This function is called internally during setup.
FUNCTION StartWaveOutStream (BYVAL param AS DWORD) AS LONG
This function allows you to play tracks simultaneously instead of sequencial. However in the actual implementation you may still encounter glitches during playback, if your PC does'nt meet speed requirements. We are heavily working to get this straight... Sofar it works glitchfree only on very specific (and fast) machines and soundcards.
The function returns %True if succesfull, %False if unsuccessfull. If waveoutstreaming could not be activated because there where still audiotracks playing or queued up for playing, the function will returns a negative number corresponding to the number of playing/queued tracks. In the latter case you should poll the function until it returns %True.
Parameters are:
- %AudioStreamCallBack = try audiostreaming from within the waveoutcallback: the callback triggers the chunkmixer
- %AudioStreamThread = try audiostreaming using a thread to perform the mixing of chunks (internal experiment)
- %AudioStreamStop = stop wave-outstreaming.
The function works in conjunction with MixChunk(togbuf) in the callback. We got it working without using dsound.dll, a library that presupposes the use of Microsoft foundation classes, too much overhead for our purpose... If readers are interested in trying to improve our approach, please feel free to contact the author.
This is the internal DLL procedure performing the audiostreaming for a maximum of 16 simultaneous audiotracks. It should never we called directly by the user.
Thus functions returns a pointer to the Audioformat structure used in the library.
This procedure should be called by GMT or its applications, to change flags in the audio structure AudioType.
We allow only setting of flags that can be set by the user application in GMT. Other flags are just updated on return.
This procedure returns the available auxiliary devices as reported by Windows on the PC.
Performs the same action as GetAuxPorts, but reports the results as a textblock that can be displayed in a window.
PrepareWaveFunctions (WavHdr() AS WAVEHDR, TrackStatus AS AudioTrackStatus)
Internal procedure called in InitGlobals in GMT. This way we know the structures as used in GMT in the DLL. Note that we wrote this in gmt_lib.bas:
GLOBAL pTrackStat AS AudioTrackStatus PTR ' - value initialized in callbacks for waveIN/OUT
GLOBAL pWbh() AS WAVEHDR PTR ' array of pointers to the the wavebufferheaders in GMT
StartAudioOutStreamThread () AS LONG
Internal function to start an audiostreaming thread. This function should not we called by users directly.
use: @pTrackStat.StreamOut = StartAudioOutStreamThread ()
StartWaveInStream (param AS LONG) AS LONG
This function starts continuous (streamed) audio input. If this function is on, recording takes place in streaming mode: continuous, using the properties for latency and buffering as set in the declared constants. (55ms input latency). Fluent continuous recording requires a reasonably fast PC. If the PC is not fast enough, glitches may be observed in the recordings.
WAVE AUDIO I/O PROCEDURES AND FUNCTIONS
AppendAudioTrack (track0 AS LONG, Track1 AS LONG)
Adds the second track to the end of the first track. The data in the second track is lost (track freed) on exit.
Mix2Tracks (track1 AS LONG, track2 AS LONG) AS LONG
This functions mixes two stereo audiotracks and rescales the result. The result will always be returned in the longest track passed. The other track will not be released on return, so the data will be preserved in the track passed.
CheckAudio (BYREF A AS AudioType,BYREF App AS ApplicationType)
This procedure should be called by GMT or its applications, in order to update the flags in Audio (as AudioType) with the values set in and used by the DLL.
BlankAudioBuffer (w AS WAVEHDR)
This procedure -residing in the DLL- can be used to fill an existing audiotrack with blanks without changing its size. With other words, it silences a track by replacing all samples with silence 'samples'. Note that this is not the same as freeing a track!
This function returns the next free audiotrack and available wavebufferheader. The tracknumber returned is 0 to 15. If no free track could be found, the function returns -1.
The function resets the .lpData, .dwBufferlength, .dwFlags in the corresponding WavHdr() structure and sets .dwUser to the free track.
NormalizeWave (Wh AS WaveHdr, procent AS DWORD) AS LONG
This function returns the maximum value encountered in the wave passed and rescales the amplitudes found according to the value passed in procent. If you pass 100% , the passed wave data will be normalized to 0dB on return.
FUNCTION SizeAudioTrack (tracknumber AS LONG, duration AS DWORD) AS LONG
This function allocates and locks memory for the audiotrack and should always be called prior to writing a track. It can also be used to delete a track and to free the memory it ate. In that case you have to pass %False for the duration. Otherwize, duration has to be expressed in milliseconds. The function set the WavHdr(tracknumber).dwbufferlength value as well as WavHdr(tracknumber).lpdata.
The function returns %False if an error occured. It returns %True if successfull.
Note: this function has been changed since version 4.20.
FUNCTION ReSizeAudioTrack (TrackNr AS LONG, duration AS DWORD) AS LONG
This function resizes an existing audiotrack preserving the existing content. Otherwize, parameters are as in SizeAudioTrack. The function sets the new size in Waveheader().dwbufferlength on exit of this procedure. If the new bufferlength is shorter than the original length, data is cut off. If bufferlength is not adjusted to a multiple of four bytes (a stereo sample in 16 bits), the function will correct this.The function returns %False if an error occured. It returns %True if successfull.
Note: this function has been changed since version 4.20.
OpenAudioInputDevice (devnr AS LONG, TrackStatus AS AudioTrackStatus) AS LONG
OpenAudioOutPutDevice (devnr AS LONG, TrackStatus AS AudioTrackStatus) AS LONG
These functions are called by the GMT setup window, to return a handle to the wave input and output devices to be used by your application. They enable the respective callback functions in the dll:
FUNCTION PlayAudioTrack (tracknumber AS LONG, flags AS DWORD) AS LONG
- Plays a memory buffer with audio samples through the opened wave output device. The handle should exist and be present in Audio.hWo prior to calling the procedure. An error will be displayed if this condition is not met. The track should contain valid wavedata.
- This function prepares the wave output header and queues it up for playing. The user has to make sure the corresponding Audiotrackx() array contains suitable data. . So, WaveBufHead.lpData will contain a data pointer to valid audio samples and WaveBufHead.dwBufferlength will reflect the size of the sample buffer on return.
- The result of the procedure is handled in the callback procedure for wave output. This procedure will unprepare the header.
- The flags can be any combination of the following declared constants:
- %WHDR_BEGINLOOP : marks the track as the beginning of an audio loop
- %WHDR_ENDLOOP: marks the end of the track as the end of an audio loop
- If only this track has to be looped, pass both constants combined through OR.
- These constants are part of the Win32Api.
- The function returns -2 if there was an fatal error.
- If successfull it returns the tracknumber playing or queued up for playing. It sets the according flags in the structure TrackStatus.playing(tracknumber).
- If the function returns -1, if the track could not be played because it is already playing , or inqueue, and if it can be called again with the same parameters.
FUNCTION PlayWaveFile (filenaam as ASCIIZ, flags AS WORD)AS LONG
- Plays a *.wav file from disk through the sound device. If audio.hwo contains a valid wave-out handle, this will be used. If no wave output device was opened, the Win32 api function playsound will be used. Note that the format of the wave file passed must be consistent with the audio settings used on initialisation of GMT. The default is 16 bit PCM Stereo with a sampling rate of 44.1kS/s.
- The flags can be one of , or a combination of following values:
- %LOOP_WAVE , il set, the wave sound will play in a loop.
- %MODULATE_VOLUME , if set allows real time volume modulation by a fadertask.
- %MODULATE_PANNING, if set allows real time panning.
- %LEFT_ONLY , if set plays the left channel only
- %RIGHT_ONLY, if set plays the right channel only
- %MODULATE_PITCH, if set allows for real time pitch modulation. This will only work if your hardware supports pitch-shifting. [This functionality is under development].
- %MODULATE_TIME, if set will allow real time stretching and condensing. [under development]
- Returns values for this function are:
- 0-15: track used for playing.
- 16: no wave handle, so the playsound function was used
- -1: file was not played because device was still busy. You can call again.
- -2: parameter or device error.
FUNCTION RecordAudioSample (duur AS DWORD) AS LONG
- TrackNumber = RecordAudioSample (2000)
RetrieveSample (duur as dword) AS LONG
This function returns immediately with the last recorded audio chunk.
If duur (duration expressed in ms) is larger than the audiobufferdepth (set by %AudioBufferSize) , the function will return a copy of the complete recordingbuffer. The function returns a tracknumber. If recording is not initialized and active, the function will fail.
RetrieveInputwave(param as dword, Sp()) as LONG
This function returns immediately with the last recorded audio chunk (always 55ms, or the value corresponding to the value set by the constant %lStreamInLatency). This function returns a normalized wave as an array of singles. You should pass a pointer to the array to receive the data in Sp(). DIM Sp(0 TO 0) as SINGLE, prior to calling this function meets this condition.
The parameter lets you specify some details:
param bit 0 = left channel wave data will be returned in Sp()
param bit 1 = right channel,
param bit 2 = mix of both channels
param bit 3 = apply LowPass for highest note 96 (midi units)You can use the predefined constants, defining bit positions, as parameter values:
%LeftChannel = 0
%RightChannel = 1
%MixChannels = 2
%ApplyLowPass = 3Audioinput streaming must have been initialized and active in order for this function to be successfull.
- Task prototype for real time fader controll of the auxdevice. The duration for the fade to be performed should be passed in Task().duur and should be expressed in milliseconds.
- The tasknumber as well as the slider ID should be set prior to activating the task, in the global structure: AudioFaders.auxtasknr and AudioFaders.auxID.
- This structure is filled and updated by the task in the following fields:
- AudioFaders.auxrightvolume
- AudioFaders.auxleftvolume
- The endposition for the faders should be set in the fields:
- AudioFaders.auxrightendvolume
- AudioFaders.auxleftendvolume
- The task will run until the duration passed is over. The sliders will move in linear intervals. The update rate is hardcoded at 12 steps per second.
- When the duration and final positions of the left/right faders is reached, the task will stop and release itself.
- Task prototype for real time fader controll of the auxdevice. The duration for the fade to be performed should be passed in Task().duur and should be expressed in milliseconds.
- The tasknumber as well as the slider ID should be set prior to activating the task, in the global structure: AudioFaders.playtasknr and AudioFaders.playID.
- This structure is filled and updated by the task in the following fields:
- AudioFaders.playrightvolume
- AudioFaders.playleftvolume
The endposition for the faders should be set in the fields:
- AudioFaders.playrightendvolume
- AudioFaders.playleftendvolume
- The task will run until the duration passed is over. The sliders will move in linear intervals. The update rate is hardcoded at 12 steps per second.
- When the duration and final positions of the left/right faders is reached, the task will stop and release itself.
FUNCTION ReadWaveData (filenaam AS ASCIIZ) AS LONG
- This function reads a 16 bit stereo wave file (44.1kS/s) from disk into a memory buffer (Audiotrack). If the function was succesfull, you can manipulate the data in memory in your code and, of course, play it back from memory to the waveoutput device selected. Of course you can also save it to disk again . The function selects automatically the next free audiotrack and sets the relevant parameters in WavHdr(x) . On return, the length of the buffer will be found in WavHdr(x).dwBufferlength, the wave data pointer in wavHdr(x).lpData. The audiotrack will be in AudioTrackx(), inside the DLL's workspace.
- If successfull, the functions returns the tracknumber used (0 to 15) and filled, else, it will return -1.
- The function does not check for validity of filename passed. So it is up to the user to do this prior to calling the function.
- To play the file read, use the function PlayAudioTrack().
FUNCTION WriteAudioTrack (filenaam AS ASCIIZ, Wh AS WAVEHDR) AS LONG
(this function replaces the former: WriteWaveData (filenaam AS ASCIIZ, BYVAL lpWaveData,BYVAL dwWavedataSize AS DWORD, BYREF AudioFormat AS WaveformatEx) AS LONG)
- This function -residing in the dll- writes wave data from a memory buffer to disk. The memory buffer should contain 16bit stereo PCM encoded 44.1kS/s audiosamples, as set on initialisation in the global structure AudioFormat. lpWaveData should contain a pointer to the sample data in memory, dwWavedataSize, should contain the exact length of the data. Both parameters can be found in the .lpData and .dwBufferlength fields of the WaveBufferHeader used.
- Note that this function does not strictly require an audio track. Any buffer with audio data can be saved. To save audiotracks it is advised to rather use the function SaveAudioTrack (), since it checks more conditions and internally calls WriteWaveData in any case. The Audioformat structure is normally filled in GMT, where it is declared as global. It is not global inside the dll however, its settings should be passed to the DLL using the procedure SetAudio (). You can retrieve flags set in the dll using the procedure CheckAudio ().
- The function returns %True, if successfull. If unsuccessfull, the function returns %False. It does not change any flags in the TrackStatus structure.
FUNCTION SaveAudioTrack (filenaam AS ASCIIZ, tracknumber as LONG) AS LONG
- This function does the same thing as WriteAudioTrack, but is much easier to use as you can suffice to pass a tracknumber as parameter directly. This function also checks conditions, such as the buffer being queued up for playing...
- If successfull, the function returns %True.
- If unsuccessfull, the function returns %False or -1. In case the returns value is %False, you should not retry calling the function with the same parameters, since there must have been an error. In the return value is -1, the track is still busy playing or queued up for playing. You may call the function again -in a thread or as a task- until it returns %True.
This function releases the track saved on return. Thus trackdata is lost. It sets all relevant flags in the TrackStatus structure.
FUNCTION CopyAudioTrack (track AS LONG, duur AS LONG) AS LONG
This function returns a copy of the track passed in a new track, returned by its number if successfull.
SUB Ringmodulate (WAVEHDR, freqleft, freqright)
SUB RingModulateTrack (Track,freqleft,freqright)
This procedure implements a true and classic ringmodulator. The left channel of audiodata in the track passed is ringmodulated with a sinewave of frequency passed in freqleft. The right channel is ringmodulated with a sinewave of frequency passed in freqright. The calculation is performed in place, thus the procedure changes the input wavebuffer and passes the result in the track passed on entry.
SUB CrossTimeModulate (WAVEHDR)
SUB Reverse (BYREF WaveIbufferheader AS WAVEHDR, BYREF WaveObufferheader AS WAVEHDR)
SUB Varispeed (WAVEHDR,WAVEHDR)
1.- The WaveIbufferheader should exist in a created and valid audio track. Say, you have an audiotrack as i. So, WavHdr(i).dwBufferlength will reflect the size of the input data.
2.- Then , get a free new audiotrack for the result:
NewTrack = GetFreeAudioTrack
3.- check NewTrack (must be > -1)
4.- Now set the size for the wavebuffer in the new track:
WavHdr(NewTrack).dwBufferlength = DWORD(WavHdr(i).dwbufferlength * faktor!)
If faktor! is > 1 then, we will slow down and stretch the original sound, if factor! is taken < 1 , then we will speed up and shorten the original sound. We do not pass factor as a parameter, since it is safer to recalculate in from the proportion of the size of the respective buffers. It will be clear that if factors derived from 12th root of 2 are used, we can implement a 16bit stereo sample player quite easily using this procedure...
FUNCTION AmplitudeModulate(tracknr&,fl!,fr!,d1!,dr!) AS LONG
This function performs amplitudemodulation on the two channels of the track passed. The modulation frequencies should be passed in fl! and fr! (resp. for the left and right channels) and the modulation depth (normalized to 0-1) in dl! and dr!, again for the left and the right channels.
SUB DeglitchStart (Wh AS WAVEHDR)
SUB DeglitchTail (Wh AS WAVEHDR)
SUB DeglitchTrack (TrackNr AS LONG)
Deglitchtrack is a macro, calling both previous functions in a row. You only have to pass the appropriate track as a parameter.
SUB FadeTrack (Tracknr AS LONG,fadeintime AS DWORD, fadeouttime AS DWORD)
This procedure recalculates the wavedata such as to produce a fade-in over a duration given by fadeintime (expressed in milliseconds), and a fadeout at the end given by fadeouttime. If you want only one of both fades, you should pass %False as time parameter for the unwanted fade. If the sum of requested fade-times exceeds the length of the track, the fade will be evenly distributed over the entire track. If this happens with one of the durations set to zero, you will get a decrescendo or a crescendo respectively over the entire duration of the track.
FUNCTION LTrimWave (WAVEHDR,noiselevel AS WORD) AS DWORD
- This function returns the number of bytes the wave data passed in wavehdr have been shifted to the left such that after calling the function, the new wave data allign exactly on the first occurance of a soundsample with absolute amplitude exceeding the noiselevel passed. The value returned by the function is required to resize the audiotrack.
- Normal use of this function is:
- LOCAL j AS DWORD
- j = LTrimWave (mywavebuffer, mynoisefloor)
- mywavebuffer.dwBufferlength = mywavebuffer.dwBufferlength - j
- ResizeTrack mytracknumber, mywavebuffer
SUB TrimWave (WAVEHDR, noiselevel AS WORD )
Example:
SUB TrimTrack (TrackNr AS LONG, noiselevel as word)
[in the works]
This procedure performs TrimWave on the tracknumber passed and at the same time resizes the wavebuffer according to the result.
- DIM Env(0 TO 0) AS SINGLE.
factorial:
Enveloppe sampling rate
(nr. of steps fer second of audio in the Env() array) |
division factor used | factorial string to be passed |
7 | 6300 | "12220" |
14 | 3150 | "12210" |
25 | 1764 | "20220" |
49 | 900 | "02220" |
50 | 882 | "20210" |
75 | 588 | "20120" |
98 | 450 | "02210" |
100 | 441 | "20200" |
210 | 210 | "11110" |
11025 | 4 | "00020" |
22050 | 2 | "00010" |
44100 | 1 | "00001" |
ch:
linlog:
SUB WaveAddReverb (BYREF Wb AS WAVEHDR, BYVAL NulT AS DWORD, BYVAL faktor AS SINGLE)
- Using this procedure, it is possible to add reverb / echo to existing wave data contained in a given wavebuffer. To accomodate for the added length of a sound with added reverb, the user should provide the required space at the end of his sound data prior to calling the procedure. Obviously, this extra data space should be filled with zero's (silence).
- The first parameter points to the input waveheader structure. The second parameter, NulT, is the time before the first reflection starts. This is proportionate to roomsize and should be expressed in milliseconds.
The third parameter, faktor, reflects the amount of reverb. If 1 is passed, the reverb is infinite and the wave might clip... If you pass larger values than 1, the procedure will limit them to 0.9999 to avoid overflows and positive feedback.
FUNCTION WaveDuration (BYREF Wavebufferheader AS WAVEHDR) AS DWORD
- This function returns the duration of the audiobuffer expressed in milliseconds. It is assumed the wavebuffer is 16-bit stereo and 44100 S/s.
FUNCTION TrackDuration (BYVAL TrackNr AS LONG) AS DWORD
This function returns the duration of the track expressed in milliseconds. It is assumed the wavebuffer is 16-bit stereo and 44100 S/s.
This section was written in collaboration with Kristof Lauwers.
FUNCTION CalcNrOfGrains (tracknr AS LONG, Grainlength AS DWORD) AS DWORD
DIM GranAr(0 TO NrGrains -1, 0 TO GrainLength) AS [LOCAL][STATIC][GLOBAL] INTEGER
SUB GranulateTrack (BYVAL track AS LONG, BYVAL Env AS DWORD,
BYREF GranAr() AS INTEGER)
FUNCTION GranuSynth (BYREF GranAr() AS INTEGER, BYVAL Stap AS
DWORD, BYVAL stretch AS SINGLE) AS LONG
FUNCTION StretchTrack (BYVAL track AS LONG, BYVAL Grainlength
AS DWORD, BYVAL stretch AS SINGLE) AS LONG
FUNCTION GranPitchShift (BYVAL track AS LONG, BYVAL interval AS
SINGLE) AS LONG
Wave generators and oscillators:
These functions as now, serve mainly for testing puposes. In the near future we might expand them and even add audiogenerators from C-Sound, including gramular synthesis here.
FUNCTION GenerateFMdiadWave(f1!,f2!,level!,pan!,d as dword) AS LONG
This function returns a wave containing f1! and f2! frequencies (passed in Hz) synthesised with FM synthesis. The panning should be passed as a normalized value ranging from 0 to 1. The value 0.5 gives the same signal on both channels. The duration must be specified in ms. The function returns a tracknumber.
FUNCTION GenerateHarmWave(H AS HarmType,pan?,d as dword) AS LONG
This function performs a form of additive synthesis: all notes passed in Har.vel will be present in the wave returned by its tracknumber. The duration should be specified in ms.
FUNCTION GenerateSineWave(Note?,Velo?,Pan?,d as dword) AS LONG
This function returns a sine wave on both channels of the track returned. The parameters are as usual in midi synths, hence limited to 7 bits. The duration of the sinewave should be expressed in ms. The returned wave is full 16 bits, 2 channel.
AUDIO CD PROCEDURES AND FUNCTIONS (dll source code in g_mci.inc & bi)
SUB PlayCDChunk (StartPoint AS DWORD, StopPoint AS DWORD)
Plays a section of a CD. It lets the user start at any point in the CD. The handle is set on opening the device in MCIid.h. The values for StartPoint and StopPoint should be calculated using our function MCI_MAKE_TMSF (track AS BYTE, minutes AS BYTE, seconds AS BYTE, frames AS BYTE) AS DWORD. You are responsable for limiting the values to whats possible for the CD inserted in the drive. The number of tracks can be found in AudioCD.NrTracks, a global structure.
SUB PlayCDTrack (Track AS BYTE)
Plays a complete track from an audio CD. The procedure will release the driver only after the track has stopped. The mci window handle should be set to MCIiD.h. This is done on opening the mci cd device. The number of tracks can be found in AudioCD.NrTracks, a global structure.
Pauses playing of a CD track or chunk. It does not release the device handler.
Stops the playing CD and releases the driver for a new play command.
SUB CueCD (Seekpoint AS DWORD)
The Seekpoint parameter should be formatted with MCI_MAKE_TMSF (track AS BYTE, minutes AS BYTE, seconds AS BYTE, frames AS BYTE) AS DWORD prior to calling this function. This procedure sets the CD-device to the passed position. During the seek operation, all audio-out is inhibited! Note that this can take up to 1500ms on some drives. This procedure should be used to cue up a CD such that it starts immediately on a subsequent play command. Once cued up, the CD starts in a minimum of time. CD timing constraints are bound to the hardware and out of control of this (and any) software. If your requirement is to cue up the CD to either the very beginning or the very end of the inserted audio CD, you can pass the special constants in Seekpoint:
- %MCI_SEEK_TO_END
- %MCI_SEEK_TO_START
The constants are defined in the Win32 Api. To make memorizing easier, we provided two aliases (with the same value):
- %CD_START
- %CD_END.
Ejects the CD in the drive and invalidates the medium bound parameters. Not all drives support software controlled eject. The user will be notified of the function is not available. As flag will we set in the audioCD structure as well.
Closes the CD drive and updates the medium bound parameters. The procedure only supports audio CD media.Not all drives support software controlled close of the tray. The user will be notified of the function is not available.
Called on initialisation of the CD device in GMT's main setup window. It fills the structures MCIid.h, MCIid.CDid, AudioCD.NrTracks etc... The relevant structures can be found in GMT_TYPE.BI
FUNCTION GetCDTrackDuration (TrackNr AS BYTE) AS DWORD
Returns the duration of a given CD track. Not all CD drives support this MCI function call! You will be notified with a message if your driver does not support the function. The function returns a value expressed in ms.
FUNCTION GetCDDuration () AS DWORD
Returns the total playing duration for the audio CD inserted in the drive. The return value is expressed in seconds.
FUNCTION MCI_MAKE_TMSF (track AS BYTE, minutes AS BYTE, seconds AS BYTE, frames AS BYTE) AS DWORD
FUNCTION Xlat_TMSF_2_ms (TMFS AS DWORD) AS DWORD
Creates the numeric parameters required to use with PlayCDChunk (BYVAL hWnd AS LONG, StartPoint AS DWORD, StopPoint AS DWORD) as well as CueCD(). This function is complemented with Xlat_TMSF_2_ms, converting a TMSF coded number into a value expressed in ms.
WaveDFT (Track AS LONG, offset AS DWORD, channel AS DWORD, Sp!())
Does a FFT transform over 1024 samples on the given track, starting from given offset. Make sure the track contains enough samples! For a channel value of 0 the left channel of the track will be used, for a value of 1 the right. The normalised result is returned in the array Sp!(). This array must be dimensioned (0 to 512)
before this function is called. The values in the array represent the relative strength of 42.98 Hz width frequencybands. When this function is called the first time it creates a lookup table, wich takes some time. Subsequent calls will be fast enough for real time use.
WaveDFTHiRes (Track AS LONG, offset AS DWORD, channel AS DWORD, Sp!(), lb AS LONG, ub AS LONG)
This function is similar to WaveDft, but has a resolutin of 4096 samples. The Sp!() array must be dimensioned (0 to 2048) and will represent 10.475 Hz width frequencybands. Lb and ub represent the lower and upper boundary of the part of the Sp!() array that you want to be filled in. It is recommended to limit this when possible as computing all 2048 bands takes a lot of time! Note that the highest note on a piano lies in band 340, so you only need the results in higher bands if you are interested in the spectrum of a sound. Note that this function is too slow for real-time use.
Track2Seq ( track AS LONG, lr AS LONG) AS STRING
Converts an audiotrack to a 'Seq' string (cfr. SEQ file format). The result has a 1 second resolution. This function uses a low resolution DFT algorythm.
This function is similar as Track2Seq, but it uses a higher resolution DFT transform and thus has a higher precision. Granul determines the rythmic granulation wanted, expressed in notes / second, NrNotes is the maximum number of simultaneous notes in the result, lFreq and hFreq are the upper and lower boundaries of the frequencyrange taken into account. Limiting this range will speed up the function. Not that this function is very slow and it is not suitable for real-time use.
WINDOWS MIXER RELATED PROCEDURES AND FUNCTIONS (dll source code in g_wmx.inc & bi)
WinMix_Mute (BYVAL hMix AS DWORD, BYVAL componenttype AS DWORD, BYVAL mute AS LONG) AS LONG
Mute or unmute a line in a windows mixer. hMix is the handle to the mixer, wich in <GMT> will usually be gh.wMix. Componenttype is the windows constant for the componenttype of the line you wish to mute. Set 'mute' to 1 to mute a line, to 0 to unmute a line. The function returns false if succeeded, otherwise the windows error value. This function wil not work on the windows recording mixer, where you have to select a line with the function WinMix_Rec_Select
Set The volume for a line in a windows mixer. hMix is the handle to the mixer, wich in <GMT> will usually be gh.wMix. Componenttype is the windows constant for the componenttype of the line for wich you wish to change the volume. l / r is the volume (in percent) of the left / right channel. If you give a different value for l and r the panning slider in the mixer will automaticly be adapted. When the mixer doesn't support separate control for the left and right channel, both channels are set to the value in l . This function will not work on the recording mixer, where WinMix_Rec_SetVolume should be used.
WinMix_Rec_Select (BYVAL hMix AS DWORD, BYVAL componenttype AS STRING) AS LONG
Select a line in the windows recording mixer. hMix is the handle to the mixer, wich in <GMT> will usually be gh.wMix. Unlike in the other mixer functions, componenttype here is a string indicating wich line you wish to select. You can select only one line at a time.
Valid components are:
component: selects: "MIDI" internal midi synth output "CD" CD-player output "LINE" line level input "MIC" microphone input "AUX" auxiliary device "DAT" DAT output "TELEPHONE" telephone/modem output "VIDEO" sound output from video "MIX" playing mixer output
This function is similar to WinMix_SetVolume, but controls the volume in the recording mixer in stead of the playing mixer. The same componenttype constants can be used.
WinMix_GetMute (BYVAL hMix AS DWORD, BYVAL componenttype AS DWORD) AS LONG
Returns the mute status of a line in a windows mixer. hMix is the handle to the mixer, wich in <GMT> will usually be gh.wMix. Componenttype is the windows constant for the componenttype of the line you wish to mute. This function returns 1 if the line is muted, 0 if it is not muted, or -1 is the mute status could not be retrieved.
Get the volume for a line in a windows mixer. hMix is the handle to the mixer, wich in <GMT> will usually be gh.wMix. Componenttype is the windows constant for the componenttype of the line for wich you wish to change the volume. l / r will be filled in with the volume (in percent) of the left / right channel. This function will not work on the recording mixer, where WinMix_Rec_GetVolume should be used.
WinMix_Rec_GetSelect (BYVAL hMix AS DWORD) AS STRING
Find out wich line is selected in the windows recording mixer. hMix is the handle to the mixer, wich in <GMT> will usually be gh.wMix. This function returns a string that indicates wich component is selected (see table below) Only one line can be selected at a time.
Return values are:
return value: selected: "MIDI" internal midi synth output "CD" CD-player output "LINE" line level input "MIC" microphone input "AUX" auxiliary device "DAT" DAT output "TELEPHONE" telephone/modem output "VIDEO" sound output from video "MIX" playing mixer output "NONE" no line selected "UNDEFINED" function failed to retrieve wich line is selected
This function is similar to WinMix_GetVolume, but returns the volume in the recording mixer in stead of the playing mixer. The same componenttype constants can be used.
LoadMixerSettings (filename AS STRING) AS LONG
Loads settings for the windows mixer, as written by SaveMixerSettings, from a file. The function returns %true if succeeded.
SaveMixerSettings (filenamen AS STRING) AS LONG
Saves the current Windows mixer settings to a file. The file is supposed to be formatted like the gmt.ini file. If the file does not exist yet a new file will be created. If there were allready mixersettings stored in this file they will be overwritten. Otherwise a new section will be added just before the "[EOF]" string. The start of this section will be indicated by "[MIXER]", the end by "[MIXER_END]". Do not change this mixersettingsmanually unles you know what you are doing! Consult the sourcecode in g_wmix.inc to find out how the settings should be formatted. The function returns %true if succeeded.
Valid componenttypes for the windows mixer functions:
Windows constant: selects device: %MIXERLINE_COMPONENTTYPE_DST_DIGITAL digital device %MIXERLINE_COMPONENTTYPE_DST_LINE line level out %MIXERLINE_COMPONENTTYPE_DST_MONITOR monitor %MIXERLINE_COMPONENTTYPE_DST_SPEAKERS speakers (= master volume) %MIXERLINE_COMPONENTTYPE_DST_HEADPHONES headphones %MIXERLINE_COMPONENTTYPE_DST_TELEPHONE telephone / modem %MIXERLINE_COMPONENTTYPE_DST_WAVEIN wave in %MIXERLINE_COMPONENTTYPE_DST_VOICEIN voice input %MIXERLINE_COMPONENTTYPE_SRC_DIGITAL digital device %MIXERLINE_COMPONENTTYPE_SRC_LINE line level in %MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE microphone %MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER internal midi synth %MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC cd-player
Sample code for recording and playback without using audio I/O streaming:
SUB RecordPlayback
' demo code for a simple real time audio I/O task under GMT
' You have to select both wave input and output devices in the setup menu.
' The constant %demo_recplay must have been set elsewere to a suitable tasknumber.
STATIC jumpval AS DWORD
STATIC TrackNr AS LONG
LOCAL retval AS LONG
IF (Task(%Demo_RecPlay).switch AND %TASK_BUSY) = %d1 THEN EXIT SUB
IF Task(%Demo_Recplay).tog = %False THEN
IF ISFALSE Audio.hWi THEN Stoptask %Demo_RecPlay
CheckAudio Audio, App
Task(%Demo_Recplay).tog = %True
jumpval = %False
END IF
SELECT CASE jumpval
CASE %False
Task(%Demo_RecPlay).duur = 500 + (RND(1) * 5000) ' in ms
TrackNr = RecordAudioSample (Task(%Demo_RecPlay).duur) ' random recording durations...
SELECT CASE TrackNr
CASE -2 ' fatal error
StopTask %Demo_RecPlay
EXIT SUB
CASE -1 ' try again later...
jumpval = %False
Task(%Demo_RecPlay).freq = 10
EXIT SUB
CASE 0 TO 15
' optional: Audio.ToDisk = %True ' set the flag for recording to disk
' we can also play the track from memory
SetAudio Audio ' publish to dll
Task(%Demo_RecPlay).freq = 1000!/(Task(%Demo_Recplay).duur - 10)
jumpval = %True
EXIT SUB
END SELECT
CASE %True
' wait until the recording is done...
IF TrackStatus.Recording(tracknr) THEN
Task(%Demo_RecPlay).freq = 20
EXIT SUB
END IF
IF Audio.ToDisk THEN
' This playback will only work if saving is switched on.
CheckAudio Audio, App
Tracknr = PlayWaveFile ("GMT_" + HEX$(Audio.iCnt-1) + ".WAV" + CHR$(0), %Null)
IF Tracknr < 0 THEN EXIT SUB
Jumpval = 2
Task(%Demo_RecPlay).freq = 1000!/(Task(%Demo_RecPlay).duur - 10)
EXIT SUB
ELSE
retval = PlayAudioTrack (TrackNr, 0)
' if called as a function the return value should equal TrackNr
IF retval = TrackNr THEN
Jumpval = 2
Task(%Demo_RecPlay).freq = 1000!/(Task(%Demo_RecPlay).duur -10)
EXIT SUB
ELSEIF retval = -2 THEN
StopTask %Demo_RecPlay ' error
ELSE
Jumpval = %True
Task(%Demo_RecPlay).freq = 20
EXIT SUB
END IF
END IF
CASE 2
' wait until playback is done:
' CheckAudio Audio, App
Task(%Demo_RecPlay).freq = 20
IF TrackStatus.Playing(tracknr) THEN EXIT SUB
Jumpval = %False
END SELECT
END SUB
Filedate: 990301/2007-01-20
<Index > | <Introduction> | <General Functions> |
<Fuzzy Functions> | <Analysis Functions> | <Acoustical Functions> |
<Visualisation Functions> | <File Management> | <Spectral Functions> |
To homepage dr.Godfried-Willem RAES |