TSignalIn Class

Header: Dew.Signal.Audio/AudioSignal.h · Cross-compiler
tObject→TMtxComponent→TAnalysis→TSignal→TAudioSignal→TSignalIn

class TSignalIn : public TAudioSignal;

Record data from an audio card.

Use TSignalIn for recording of audio data. There are two ways to receive an audio stream from the component. One is via the Pull method, which is called each time a new buffer is filled once the processing has started. The Pull method is called only, if AutoPull property is True. The other method uses the OnBufferFilled event. In both cases the audio data stream is placed in Self.

The component features two very important functions: Monitor and Trigger. Together with the double buffered processing, this functions make it possible to monitor a recording currently in progress and catch Trigger conditions, while the recording data is being streamed to disk.

The audio driver requires at least two buffers. While it is writing in the first one, the user can copy data from the second one. When the first buffer is full, the driver starts to write in the second buffer and the user can copy data from the first one. This process is transparent to the user. When a new full buffer becomes available a Pull method will called, if AutoPull is True. If AutoPull is false and OnBufferFilled event is assigned this event will be called. If even the event is not assigned, then there will be no notification to the user when an audio buffer becomes full. The user can still call the Monitor function to obtain the latest data from the audio buffers.

The Monitor function copies data from the (audio) buffers, before the buffer is full. This is possible by calling a special WINAPI function GetWavePosition, which returns the number of samples recorded so far. This allows TSignalIn component to compute where in the buffer is the sound driver currently putting the samples. The advantage of this approach is, that the user does not have to wait for the buffer to become full, before he gains access to the data within that buffer. This means, that the delay between the event (when the signal changes) and the time when the this event becomes visible on the screen can be very short. With FFT Properties, this delay can be less then 0.1 s. Such short delays are not possible when you have to wait until a buffer is full.

Typically, a single buffer must be about 0.5 seconds long to prevent sample skipping. Alltogether there are usually 4 buffers: 4*0.5 = 2 seconds. This 4 buffers determine how long data blocks can be copied by the Monitor function. They can not be longer then 2 seconds in case of 4 buffers with each holding 0.5 seconds. FFT Properties uses a timer that calls the Monitor function. The clock of this timer is almost independent of the buffer size or recording parameters.

Once the buffer gets full, it will not be displayed on the screen, because the Monitor function already did that part of the job. The job that the Monitor function can not do, is provide a steady continuous non-overlapping stream of data. This is what we get when buffers get full. We get non-overlapping blocks of data ready to be written to file (for example)..

One question remains. Why not having just two buffers each 1 seconds long? Or maybe each of them 5 seconds long? That would not affect how Monitor function works or its updates or the update frequency of the charts. Buffers are processed in blocks. It is therefore better to have many small buffers, because whatever processing is followed (could be a filter or sound field effect) is broken down in to smaller pieces. If buffers would be processed in big pieces, the screen update might stop for the time of processing the block. This would result in jittering chart updates (The chart updates would be smooth for 5 seconds, then it would stop for 0.5 second and again smooth for 5 seconds...).

The point of having many small buffers is to distribute the processing evenly across time.

The Trigger function works in the same way as the Monitor function. The Trigger function calls the Monitor function to obtain the most recent data from the buffers. The call frequency must be high enough, so that during the time passed between two consequtive calls, the non-processed data in the buffers is not yet overwritten with the new data. Once a call is made, all the recorded samples currently in the audio buffers are checked, if they meet the trigger condition. Once the trigger condition is found, the appropriate data (block before trigger, after trigger etc..) is be copied to the local Data buffer (passed as a parameter to the function). When the next call is made to the Trigger function, it will continue to search for the next trigger condition. Once the next trigger condition is found, the Trigger function will overwrite the data obtained previously. In the DSP for MtxVec demo, the trigger is set to not overwrite the data, once a new trigger condition is found, unless the trigger has been reset. (That is why there is a reset button.) This button only sets a flag to false. The recording in the background is running continuously.

Each time the trigger function is called, all the new data is processed, if the trigger condition is not found within that data. If the trigger condition is found, the data is not further checked from the trigger position on, until the next call is made. The trigger function remembers the position where it has stopped checking the data for the trigger condition and when the next call is made, it starts where it left off.

If one full buffer is missed (4*0.5 = 2 seconds) there is a catchUps array which counts the number of such full buffer drops. This parameter is also displayed on the time signal chart on the "trigger" form of DSP for MtxVec demo.

If the trigger condition is met for almost every sample, then the trigger could be reset 100 times per second and it would still not be enough to keep the pace with how quickly trigger conditions would be found, because the timer frequency will be lower then the frequency of trigger conditions found. With a timer set at 20Hz only 20 trigger conditions can processed per second. A typical practical application requires only one trigger reset per several seconds or more

Normally, the user would reset the trigger and then wait until trigger condition is found (for example a few seconds). Once the data is acquired, the trigger can be reset again.

Note that the Trigger function has to be called continuously with a timer whose frequency is high enough so that yet unprocessed buffers will not get overwritten with the new data and that the number of trigger conditions per second will be less then the timer frequency.

The audio driver is working in the background in its own thread. When he is given 4 buffers, the recording will be running uninterrupted until the first buffer is full. When the first buffer is full, the driver sends a message to the window, designated for receiving audio driver messages, triggering an OnBufferFIlled event. Even if the app is stalled, the audio driver will still record until it fills all 3 remaining buffers and is sending a message to the window associated with the recording each time a buffer gets full. After all four buffers have been recorded and the application is still frozen, there are 4x OnBufferFilled requests in the message queue of the application. If the application unfreezes at least a few miliseconds before the last buffer is full, and it is able to process all pending requests within that short time, the recording will continue uninterrupted. If the total length of all four buffers is 2 seconds, that means that application can be completely frozen for about 1.5- 1.8 seconds, before the recording will be interrupted.

If the Monitor function is called with a frequency of 20Hz, then after 1.5 seconds there would be 30 requests pending to be processed. If it takes about 20% of the CPU to process 20 requests per second, that means that it takes only 0.2 seconds for the CPU to do its work and the app could be halted for 1.8 seconds, before the recording would be affected. If the total size of all recording buffers is increased to 10 seconds then it would take 9 seconds of a complete application freeze, before the recording would stop. The buffers should be short and there should be many of them, to distribute the processing across time, if longer total audio buffer length is desired.

Constructors

NameDescription
TSignalIn (2)

Properties

NameTypeDescription
Activebool
AutoPullboolSet the property to True, for the component to call Pull method each time a new buffer is requested.
BandWidthdoubleReturn the bandwidth of the signal.
BandwidthHdoubleReturns the upper bandwidth edge of the signal.
BandwidthLdoubleReturns the lower bandwidth edge of the signal.
BlockAssignboolBlock streaming of specific properties when storing only a "template".
BufferSizeint
CalibrationTargetintUsed for calibration of the input amplification.
ChannelCountintGet or set the number of channels multiplexed in the data property.
ComplexboolSet this property to true, to request computation using complex numbers.
ContinuousboolIf True, the component will pass on the udpate request to the connected component.
DataTVec*Stores the result of the processing.
DtdoubleTime between two consecutive samples.
EditorActiveboolReturns True, if the component editor is displayed.
FloatPrecisionTMtxFloatPrecisionSet this property to request computation in 32bit/64bit precision with real/complex numbers.
FloatPrecisionLockboolSet this property to true to lock changes to FloatPrecision property.
HzResdoubleFrequency resolution obtained, if an FFT algorithm would be run on the data.
InputTSignal*
InputsTSignalCollection*
IsDoubleboolSet this property to false, to request computation in 32bit floating point precision, 64bit, if true.
ItemNumberintNumber to label the object when it is an item in the List.
LengthintGet or set the length of the signal in samples.
MarksTMarkList*Stores the time stamps and amplitude of selected samples.
MaxAmpltdoubleStores the maximum amplitude of the signal found by the MinMax method.
MaxXdoubleUse the MaxX property to store the time stamp (in seconds) of the right most sample.
MinAmpltdoubleStores the minimum amplitude of the signal found by the MinMax method.
MinXdoubleUse the MinX property to store the time stamp of the left-most sample.
MonitorAggressivenessintDefines how aggressivelly will the MonitorData function attempt to obtain the very latest data (just to be recorded or just to be played back.) The value is defined in miliseconds.
MonitorFreqfloatThe property keeps the track of the actual frequency of the calls to the MonitorData property.
MultiChannelboolSet MultiChannel to True, if Inputs property will be published, and Input property will remain hidden.
NameDewString
NumBuffersintDefines number of buffers being gueued to be processed.
OnAfterUpdatetNotifyEventThe event is triggered after the call to the Update method.
OnBeforeUpdatetNotifyEventThe event is triggered just before the call to the Update method.
OnBufferFilledTBufferInEventCalled each time a new buffer of data is available.
OnDisplayUpdatetNotifyEventThe event is triggered after the OnAfterUpdate event. Use this event to update any associated charts or graphs or result tables.
OnGetInputtNotifyEventIf the Input property is not assigned, the component will call OnGetInput.
OnNotifyUpdatetNotifyEventThe event is called after a call to InternalUpdate, OnAfterUpdate and OnDisplayUpdate from within the Update method.
OnParameterUpdatetNotifyEventThe event is triggered when ParamUpdate method is called. The ParamUpdate method is usually called by component editors when a value was changed by the user and the editor was "Live".
OnStarttNotifyEventEvent triggered when processing starts.
OnStoptNotifyEventEvent triggered when processing stops.
OverlappingfloatThe property holds the statistics for the MonitorData method.
PausedboolSet it to true, if you want to pause the playback.
PipeDirtybool
PipeStateTPipeStateReturns the state of the pipe after the last update.
Quantizationunsigned shortDefine dynamics of the signal. 8,16 or 24 bit.
ReferenceTReferenceList*Stores a list of components that have to be notified, when this component is destroyed.
SamplingFrequencydoubleDefines the sampling frequency of the signal.
SamplingTimedoubleThe length of the signal in seconds.
SuspendNotifyUpdateboolSet this property to True, to prevent calling OnNotifyUpdate from the Update Method.
TriggerAbovedoubleDefines the level above which the signal must rise before the trigger will condition will be true.
TriggerBelowdoubleDefines the level below which the signal must fall before the trigger will condition will be true.
TriggerChannelTChannelSpecifies the channel that will be searched for trigger condition.
TriggerDelayintDefines the delay in number of samples.
TriggeringTTriggerUsed to enable and disable the trigger logic.
TriggerModeTTriggerModeDefines the trigger condition to be searched for in the signal.
TriggerPositionTTriggerPositionDefines which data to return after trigger relative to the trigger position .
UsesInputsbool
WaveDeviceintSet WaveDevice to -1, to always use default windows sound device.

Methods

NameDescription
AllowStreaming
AppendAppends Sample to the end of the signal.
Assign
AssignTemplateAssign values of "template-like" published properties from Source.
CloseWaveDevice
CopyCopies signal Data and sampling frequency information.
CrestCompute the CREST parameter.
DetectChannelCount
EditorClass
ElapsedSamplesThe function returns the total samples count elapsed since the start of the recording.
ElapsedTimeThe function returns the total time elapsed in seconds since the start of the recording.
get_CValues
get_Values
GetDeviceListReturns a list of Audio devices.
GetInput
GetInputs
InputsDirtyIf all Inputs[i] are dirty the function returns true.
InternalPull
InvalidateNotifies all connected components that this component has fresh data.
LoadFromStreamLoad the component from Src stream.
LoadTemplateFromFileLoad a template from file.
LoadTemplateFromStreamLoad a template from stream.
MakeWaveFmtConsistent
MarksToStringsConvert marks to strings.
MinMaxFind minimum and maximum amplitude and store the result in the MinAmplt and MaxAmplt properties.
MonitorData (2)Call MonitorData to obtain data just to be played or just recorded for input/output monitoring purpose.
MonitorOutput
ParamUpdateThe method can be assigned to some other component even handler, as a notification that a parameter has changed and that Self should consider a recalculation.
PeakFind the maximum deviation of the signal from its mean value.
PipeResetRecursively processes all connected components backward and calls Reset method.
ProcessBuffer
PullRequest recalculation of the entire chain of all connected components.
PullUntilEndCalls Pull until pipeEnd is returned.
QueueBuffer
RecomendedBufferLengthTo ensure skip free recording an playback, audio buffers must have some minimum size.
RecomendedBufferSizeTo ensure skip free recording an playback, audio buffers must have some minimum size.
ReferenceRemoved
Reset
ResetCatchUpsInitialize TriggerCatchUps array to zero.
ResetTriggerSets the Triggered property to false and sets to search range to the last recorded sample.
ResetTriggerCountInitialize TriggerCount array to zero.
ResetTriggersResets triggers for both left and right channel via ResetTrigger method.
SaveTemplateToFileSave template to file.
SaveTemplateToStreamSave template to stream.
SaveToStreamSave the component to Dst stream.
set_CValues
set_Values
SetChannelCountSets the value of TSignal.ChannelCount property.
SetComplex
SetFloatPrecision
SetInputs
SetIsDouble
SetQuantization
SetSamplingFrequencySet the value of the TSignal.SamplingFrequency property.
SetTriggering
Setup
SizeAssign the size of the signal from Src.
SoftResetTriggerSets the Triggered property to false but does not adjust the search range.
SoftResetTriggersResets triggers for both left and right channel via SoftResetTrigger overloaded method.
StartStart recording.
StartIt
StereoReturns True, if the signal is Stereo.
StopAtOnce
StopGracefully
TriggerCall Trigger function with a frequency high enough, so that wave data buffers will not get overrun.
UpdateRecalculate request.
UpdateNotifyCall this method only, if SuspendNotifyUpdate is True.
Values
ValuesToStringsConvert values to strings.

Operators

NameDescription
operator[]

Fields

NameTypeDescription
ATimeSignalTSignal *
BufIndexint
ContinueProcessingbool
ErrorMessageDewStringThe property holds any error message after an error has occured.
FAutoPullbool
fBitsPerSampleunsigned short
FBufferSizeint
FCalibrationTargetint
FCatchUpsunsigned int
FilledBuffersintNumber of buffers filled with data to be processed, since the start of the processing.
FMonitorAggressivenessint
FMonitorFreqfloat
FNumBuffersint
fOldSearchRangeDewArray<int>
FOnBufferInFilledTBufferInEvent
FOnStarttNotifyEvent
FOnStoptNotifyEvent
FOverlappingfloat
FPausedbool
FRequestedBufferSizeint
FTriggerTTrigger
FTriggerAbovedouble
FTriggerBelowdouble
FTriggerChannelTChannel
FTriggerDelayint
FTriggerModeTTriggerMode
FTriggerPositionTTriggerPosition
FWaveDeviceint
FWaveFmtExTWaveFormatExtensible
FWindowHandlehWnd
GetAllowedbool
GetPointerintPtr
GetSizeint
hWaveBufferDewArray<intPtr>
ProcessedBuffersintNumber of buffers actually processed, since the start of the processing.
PWaveHeadersDewArray<PWaveHdr>
QueuedBuffersintNumber of buffers queued, to be processed, since the start of the processing.
Tagintptr_t
TriggerCatchUpsDewArray<int>Array elements contain the count of trigger catch-ups on each channel.
TriggerCountDewArray<int>Array elements contain the count of trigger conditions meet on each channel.
TriggeredDewArray<bool>Array elements are True, if the coresponding channels have triggered. Index 0 is the left channel and 1 is for the right channel.
TriggerSampleint
WaveBufferDewArray<intPtr>
WaveDeviceOpenbool
WaveHandleHWaveOutWaveform output handle.