Yet another SimpleAudioLogger

let me try to summarize what I have understood how the threshold works:

1.) highpass filter the incoming audio block: aux(t) = (data(t) - data(t -1)) * (data(t) - data(t -1))
2.) determine maximum value of all the samples in the block --> MaxVal
3.) if MaxVal is larger than threshold --> haveSignal is set to the number of blocks to be sent (MIN_BLOCKS). From my understanding this would determine the length of the recording after a triggered recording is started, does it? [so three blocks means only roughly 8msec at 48ksps sample rate!?]
4.) as long as haveSignal is larger/equal to 0, audio block of the preceding round is transmitted, the recent audio block will be sent next round. This ensures that an audio snippet that triggers the recorder, will not be lost, but preserved (one audio block is 128 samples, so using a sample rate of 48ksps, we have a pre-trigger time of 128/48000, that is 2.7msec)
5.) out blocks are released. Does this ensure that audio is thrown away, if threshold is not met?
6.) out1 = tmp1 --> save recent audio for potential transmit in next round

Would be nice to have comments / additions to that :).

Best regards,

Frank
 
The whole program is not a final product, but a framework (and a hack) to be build on.
The skeleton alone could work but I see a lot of customization necessary and possible (e.g. what to put into a header etc., )

Yes, totally agreed, and I really acknowledge that you put this in the public domain so others can mess around with that! Thats very helpful! And I would really like to contribute to the code as soon as I get the grasp of how it works ;-).

while acquiring data, the program can set to store only data of interest to uSD. At the moment a simple threshold detector is given as example and must be verified. Other processing should be possible.

From my observations, it seems the time scheduled recording overrides the threshold detector at the moment. If I set a very large threshold, the sketch records, and reports ridiculously high Audio memory usage, as if the blocks are not properly released.

Code:
180000000 48000 48004 32 16 248 1

loop:    52    0     1;
WMXZ_2018_02_29_08_48_49
loop:  2221    6 65533;
loop:  2734   11 64927;
loop:  2529   17 64177;
loop:  2727   23 63461;
loop:  2732   29 62721;
loop:  2670   35 61969;
loop:  2582   41 61289;

The recording (length one minute as set by the timer!) consists of large parts of max signal overloading and small snippets of useful audio (I suspect these are the windows in the audio when the threshold is met by the audio level).

I will try my best to understand and maybe solve this.

All the best,

Frank
 
let me try to summarize what I have understood how the threshold works:

1.) highpass filter the incoming audio block: aux(t) = (data(t) - data(t -1)) * (data(t) - data(t -1))
2.) determine maximum value of all the samples in the block --> MaxVal
3.) if MaxVal is larger than threshold --> haveSignal is set to the number of blocks to be sent (MIN_BLOCKS). From my understanding this would determine the length of the recording after a triggered recording is started, does it? [so three blocks means only roughly 8msec at 48ksps sample rate!?]
4.) as long as haveSignal is larger/equal to 0, audio block of the preceding round is transmitted, the recent audio block will be sent next round. This ensures that an audio snippet that triggers the recorder, will not be lost, but preserved (one audio block is 128 samples, so using a sample rate of 48ksps, we have a pre-trigger time of 128/48000, that is 2.7msec)
5.) out blocks are released. Does this ensure that audio is thrown away, if threshold is not met?
6.) out1 = tmp1 --> save recent audio for potential transmit in next round

Would be nice to have comments / additions to that :).

Best regards,

Frank
Yes, that sounds right
I added some comments to that purpose
Only correction is that MIN_BLOCK==3 should transmit 3 blocks centered around triggered block (pre, triggered, post)
A value of 4 would generate (pre + triggered + 2 post)
 
From my observations, it seems the time scheduled recording overrides the threshold detector at the moment. If I set a very large threshold, the sketch records, and reports ridiculously high Audio memory usage, as if the blocks are not properly released.

Code:
180000000 48000 48004 32 16 248 1

loop:    52    0     1;
WMXZ_2018_02_29_08_48_49
loop:  2221    6 65533;
loop:  2734   11 64927;
loop:  2529   17 64177;
loop:  2727   23 63461;
loop:  2732   29 62721;
loop:  2670   35 61969;
loop:  2582   41 61289;

The recording (length one minute as set by the timer!) consists of large parts of max signal overloading and small snippets of useful audio (I suspect these are the windows in the audio when the threshold is met by the audio level).

I will try my best to understand and maybe solve this.

Yes, the (negative) numbers indicate that there are more blocks released than allocated (I will chase the bug)
 
Frank,

I removed the bug, that was in the multiplexer
I added some comments to code (and corrected the transmission criterion)
I added also a watchdog that transmits regularly a block even if there is no detection.
Also, I added a marker to the beginning of every group of transmissions that indicates the acquisition block count in lieu of a time stamp.
 
Walter,

thank you! OK, I understand, the multiplexer remained active and sent audio data to the queue, so the sketch kept on writing to the SD card, even when the process1 refused to deliver more blocks and therefore garbage was written . . . thanks for the fix!

I wanted to try to summarize the action taking place in process1, but I have not understood the code so far, I need a little more time, sorry.

But I can report some observations:

One observation:
haveSignal goes to highly negative values, depending on the predefined MIN_DELAY, although from my understanding it should go to -1 and remain there . . .
When the incoming audio exceeds the threshold, it goes to positive values again. This log made with MIN_DELAY 377, MIN_BLOCKS 375 --> one second of recording after a trigger event occured:

Code:
180000000 48000 48004 32 16 248 1

loop:   314    0  333    11;
WMXZ_2018_02_29_14_14_16
loop:  2707    6  120    19;
loop:  2612   12 -256    11;
loop:  2685   14 -377    11;
loop:  2758   14 -377    10;
loop:  2750   14 -377    10;
loop:  2567   16  219    11;
loop:  2723   20  373    11;
loop:  2736   26  360    11;
loop:  2654   32  276    11;
loop:  2608   36  -99    11;
loop:  2760   36 -377     8;

Also, there seems to be a bug affecting only one of the audio channels, see this recording, which has several successfull trigger events in it:

Audio_logger_WMXZ.jpg

One channel has a cumulative audio value in it!?? Maybe related with the writing of a count variable into the audio data? I have not understood the purpose of that . . .

I am also not quite sure whether we have the same idea of the intended functionality in our heads.

The logger has two modes at the moment:

1.) time-triggered logging
Thats the base functionality you had already built in the original version: define time windows (eg. sunrise / sunset) and then record in those time windows for one minute and pause for four minutes or something similar.

2.) sound-level triggered recordings: define define time windows (eg. sunrise / sunset) and a number of samples that are being recorded whenever the soundlevel exceeds the threshold. This is called MIN_BLOCKS at the moment. At 48ksps sample rate, a MIN_BLOCKS of 375 is the equivalent of one second.

However, the behaviour at the moment is a mixture of the two: a sound-level triggered recording to a file, where all the sound events are stuffed together and after the defined time span (one minute) of sound/no sound, the file is closed.
It would be desirable, that the trigger event triggers the beginning of the recording and then after a predefined length, the file is closed and a new file is opened, which then waits for the next trigger event. If a new trigger event occurs during recording, then the recording should be prolonged to be the predefined length from the time of that new trigger event. (Of course, we should define a maximum length of a recording, even when new triggers arrive very frequently . . .). I hope this makes some sense in a way ;-).

OK, will continue in my trial to understand your code :).

Thanks & All the best, Frank
 
Last edited:
Walter,

thank you! OK, I understand, the multiplexer remained active and sent audio data to the queue, so the sketch kept on writing to the SD card, even when the process1 refused to deliver more blocks and therefore garbage was written . . . thanks for the fix!

I wanted to try to summarize the action taking place in process1, but I have not understood the code so far, I need a little more time, sorry.

But I can report some observations:

One observation:
haveSignal goes to highly negative values, depending on the predefined MIN_DELAY, although from my understanding it should go to -1 and remain there . . .
When the incoming audio exceeds the threshold, it goes to positive values again. This log made with MIN_DELAY 377, MIN_BLOCKS 375 --> one second of recording after a trigger event occured:

Code:
180000000 48000 48004 32 16 248 1

loop:   314    0  333    11;
WMXZ_2018_02_29_14_14_16
loop:  2707    6  120    19;
loop:  2612   12 -256    11;
loop:  2685   14 -377    11;
loop:  2758   14 -377    10;
loop:  2750   14 -377    10;
loop:  2567   16  219    11;
loop:  2723   20  373    11;
loop:  2736   26  360    11;
loop:  2654   32  276    11;
loop:  2608   36  -99    11;
loop:  2760   36 -377     8;

Also, there seems to be a bug affecting only one of the audio channels, see this recording, which has several successfull trigger events in it:

View attachment 13116

One channel has a cumulative audio value in it, that is probably related with the writing of a count variable into the audio data. [if I zoom into the audacity file, I can see, that the cumulative value is one single audio sample every 128 samples]. I have not understood the purpose of writing the number of blocks to the audio data.

I am also not quite sure whether we have the same idea of the intended functionality in our heads.

The logger has two modes at the moment:

1.) time-triggered logging
Thats the base functionality you had already built in the original version: define time windows (eg. sunrise / sunset) and then record in those time windows for one minute and pause for four minutes or something similar.

2.) sound-level triggered recordings: define define time windows (eg. sunrise / sunset) and a number of samples that are being recorded whenever the soundlevel exceeds the threshold. This is called MIN_BLOCKS at the moment. At 48ksps sample rate, a MIN_BLOCKS of 375 is the equivalent of one second.

However, the behaviour at the moment is a mixture of the two: a sound-level triggered recording to a file, where all the sound events are stuffed together and after the defined time span (one minute) of sound/no sound, the file is closed.
It would be desirable, that the trigger event triggers the beginning of the recording and then after a predefined length, the file is closed and a new file is opened, which the waits for the next trigger event. If a new trigger event occurs during recording, then the recording should be prolonged to be the predefined length from the time of that new trigger event. (Of course, we should define a maximum length of a recording, even when new triggers arrive very frequently . . .). I hope this makes sense in a way ;-).

OK, will continue in my trial to understand your code :).

Thanks & All the best, Frank
 
One observation:
haveSignal goes to highly negative values, depending on the predefined MIN_DELAY, although from my understanding it should go to -1 and remain there . . .
When the incoming audio exceeds the threshold, it goes to positive values again. This log made with MIN_DELAY 377, MIN_BLOCKS 375 --> one second of recording after a trigger event occured:

Code:
180000000 48000 48004 32 16 248 1

loop:   314    0  333    11;
WMXZ_2018_02_29_14_14_16
loop:  2707    6  120    19;
loop:  2612   12 -256    11;
loop:  2685   14 -377    11;
loop:  2758   14 -377    10;
loop:  2750   14 -377    10;
loop:  2567   16  219    11;
loop:  2723   20  373    11;
loop:  2736   26  360    11;
loop:  2654   32  276    11;
loop:  2608   36  -99    11;
loop:  2760   36 -377     8;
This is correct, the printout is every second and not synchron with the acquisition, so the third column may give 'random' numbers. It has no other meaning than to see how it changes.

Also, there seems to be a bug affecting only one of the audio channels, see this recording, which has several successfull trigger events in it:

One channel has a cumulative audio value in it, that is probably related with the writing of a count variable into the audio data. [if I zoom into the audacity file, I can see, that the cumulative value is one single audio sample every 128 samples]. I have not understood the purpose of writing the number of blocks to the audio data.
Yes, the first two words in both channels in an detection block have nor a block Count.
This should help to estimate the timing of the detection.
without similar information, you do not know if the say 10 detections in a minute are all one after the other, equally spaced or randomly spaced.

An alternative would be to open a file each time for each detection, as you indicate below.

I am also not quite sure whether we have the same idea of the intended functionality in our heads.

The logger has two modes at the moment:

1.) time-triggered logging
Thats the base functionality you had already built in the original version: define time windows (eg. sunrise / sunset) and then record in those time windows for one minute and pause for four minutes or something similar.

2.) sound-level triggered recordings: define define time windows (eg. sunrise / sunset) and a number of samples that are being recorded whenever the soundlevel exceeds the threshold. This is called MIN_BLOCKS at the moment. At 48ksps sample rate, a MIN_BLOCKS of 375 is the equivalent of one second.

However, the behaviour at the moment is a mixture of the two: a sound-level triggered recording to a file, where all the sound events are stuffed together and after the defined time span (one minute) of sound/no sound, the file is closed.
It would be desirable, that the trigger event triggers the beginning of the recording and then after a predefined length, the file is closed and a new file is opened, which the waits for the next trigger event. If a new trigger event occurs during recording, then the recording should be prolonged to be the predefined length from the time of that new trigger event. (Of course, we should define a maximum length of a recording, even when new triggers arrive very frequently . . .). I hope this makes sense in a way ;-).

correct

This is IMO a question of taste. I prefer low number of files, with possible multiple detections, maybe my events are all very short. But if the events are long, a file/event is a valid solution.
 
Frank,
one complication with 1 file/event is that writing to disk is after a queue with unpredictable and variable length.
So, if the process step that works in real-time finds a signal it has somehow to pass-on the information to the uSD interface.
I have to think about it.
 
Frank,
the latest GitHub version allows for single file/event archiving.

I sent you a PM
 
Hello Walter,
Was checking your github project and it is already very complete, compared with what I remember.
Congratulations for the nices add's.
Also notice that you have an even more extensive logger the microSoundRecorder!
Have you already test this with another type of microphones that not MEMS?
I am now compiling new code for a simple logger, for use an diy hydrophone.
How did you implement the sleep function to wake after a certain period of time or you what up every minute check the time and go back to sleep,
if it is not to record?
Thanks for your help.
All the best,
Tim
 
Hello all,

First, thanks Walter, and everyone for getting this idea to work.
Second, after being away from coding for a while, I now have a need for this implementation. It took some learning to get this far as all other sketches up till now were just simple one tab programs, so figuring out header files, and the organization of multiple sketches took some time. But now it's late and I could use some help. I've got the Teensy3.6 and one ICS43434 digital microphone wired up, all sketches loaded, header files saved, but I have an issue with compiling. I get :

Code:
C:\Program Files\Arduino\arduino-builder -dump-prefs -logger=machine -hardware C:\Program Files\Arduino\hardware -hardware C:\Documents and Settings\Greg\Local Settings\Application Data\Arduino15\packages -hardware C:\Documents and Settings\Greg\My Documents\Arduino\hardware -tools C:\Program Files\Arduino\tools-builder -tools C:\Program Files\Arduino\hardware\tools\avr -tools C:\Documents and Settings\Greg\Local Settings\Application Data\Arduino15\packages -built-in-libraries C:\Program Files\Arduino\libraries -libraries C:\Documents and Settings\Greg\My Documents\Arduino\libraries -fqbn=teensy:avr:teensy36:usb=serial,speed=96,opt=o2std,keys=en-us -ide-version=10805 -build-path C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037 -warnings=none -build-cache C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_cache_201326 -verbose C:\Documents and Settings\Greg\My Documents\Arduino\microSoundRecorder\microSoundRecorder.ino
C:\Program Files\Arduino\arduino-builder -compile -logger=machine -hardware C:\Program Files\Arduino\hardware -hardware C:\Documents and Settings\Greg\Local Settings\Application Data\Arduino15\packages -hardware C:\Documents and Settings\Greg\My Documents\Arduino\hardware -tools C:\Program Files\Arduino\tools-builder -tools C:\Program Files\Arduino\hardware\tools\avr -tools C:\Documents and Settings\Greg\Local Settings\Application Data\Arduino15\packages -built-in-libraries C:\Program Files\Arduino\libraries -libraries C:\Documents and Settings\Greg\My Documents\Arduino\libraries -fqbn=teensy:avr:teensy36:usb=serial,speed=96,opt=o2std,keys=en-us -ide-version=10805 -build-path C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037 -warnings=none -build-cache C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_cache_201326 -verbose C:\Documents and Settings\Greg\My Documents\Arduino\microSoundRecorder\microSoundRecorder.ino
Using board 'teensy36' from platform in folder: C:\Program Files\Arduino\hardware\teensy\avr
Using core 'teensy3' from platform in folder: C:\Program Files\Arduino\hardware\teensy\avr
WARNING: Category 'Utility' in library FlexIO_t4 is not valid. Setting to 'Uncategorized'
Detecting libraries used...
"C:\Program Files\Arduino\hardware\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w  -g -Wall -ffunction-sections -fdata-sections -nostdlib -mno-unaligned-access -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -D__MK66FX1M0__ -DTEENSYDUINO=156 -DARDUINO=10805 -DARDUINO_TEENSY36 -DF_CPU=96000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\Program Files\Arduino\hardware\teensy\avr\cores\teensy3" "C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037\sketch\microSoundRecorder.ino.cpp" -o "nul"
"C:\Program Files\Arduino\hardware\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w  -g -Wall -ffunction-sections -fdata-sections -nostdlib -mno-unaligned-access -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -D__MK66FX1M0__ -DTEENSYDUINO=156 -DARDUINO=10805 -DARDUINO_TEENSY36 -DF_CPU=96000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\Program Files\Arduino\hardware\teensy\avr\cores\teensy3" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Audio" "C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037\sketch\microSoundRecorder.ino.cpp" -o "nul"
"C:\Program Files\Arduino\hardware\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w  -g -Wall -ffunction-sections -fdata-sections -nostdlib -mno-unaligned-access -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -D__MK66FX1M0__ -DTEENSYDUINO=156 -DARDUINO=10805 -DARDUINO_TEENSY36 -DF_CPU=96000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\Program Files\Arduino\hardware\teensy\avr\cores\teensy3" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Audio" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Time" "C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037\sketch\microSoundRecorder.ino.cpp" -o "nul"
"C:\Program Files\Arduino\hardware\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w  -g -Wall -ffunction-sections -fdata-sections -nostdlib -mno-unaligned-access -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -D__MK66FX1M0__ -DTEENSYDUINO=156 -DARDUINO=10805 -DARDUINO_TEENSY36 -DF_CPU=96000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\Program Files\Arduino\hardware\teensy\avr\cores\teensy3" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Audio" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Time" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\SdFat\src" "C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037\sketch\microSoundRecorder.ino.cpp" -o "nul"
"C:\Program Files\Arduino\hardware\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w  -g -Wall -ffunction-sections -fdata-sections -nostdlib -mno-unaligned-access -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -D__MK66FX1M0__ -DTEENSYDUINO=156 -DARDUINO=10805 -DARDUINO_TEENSY36 -DF_CPU=96000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\Program Files\Arduino\hardware\teensy\avr\cores\teensy3" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Audio" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Time" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\SdFat\src" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\SPI" "C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037\sketch\microSoundRecorder.ino.cpp" -o "nul"
"C:\Program Files\Arduino\hardware\teensy/../tools/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w  -g -Wall -ffunction-sections -fdata-sections -nostdlib -mno-unaligned-access -fno-exceptions -fpermissive -felide-constructors -std=gnu++14 -Wno-error=narrowing -fno-rtti -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -D__MK66FX1M0__ -DTEENSYDUINO=156 -DARDUINO=10805 -DARDUINO_TEENSY36 -DF_CPU=96000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\Program Files\Arduino\hardware\teensy\avr\cores\teensy3" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Audio" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\Time" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\SdFat\src" "-IC:\Program Files\Arduino\hardware\teensy\avr\libraries\SPI" "C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037\sketch\microSoundRecorder.ino.cpp" -o "C:\DOCUME~1\Greg\LOCALS~1\Temp\arduino_build_187037\preproc\ctags_target_for_gcc_minus_e.cpp"
C:\Documents and Settings\Greg\My Documents\Arduino\microSoundRecorder\myAPP.cpp.ino:68:20: fatal error: config.h: No such file or directory

compilation terminated.

Using library Audio at version 1.3 in folder: C:\Program Files\Arduino\hardware\teensy\avr\libraries\Audio 
Using library Time at version 1.6.1 in folder: C:\Program Files\Arduino\hardware\teensy\avr\libraries\Time 
Using library SdFat at version 2.1.0 in folder: C:\Program Files\Arduino\hardware\teensy\avr\libraries\SdFat 
Using library SPI at version 1.0 in folder: C:\Program Files\Arduino\hardware\teensy\avr\libraries\SPI 
Error compiling for board Teensy 3.6.

What is perplexing is that the config.h file is right there in the folder along with all the others. Not sure what is going on.

Thanks
Greg
 
What is perplexing is that the config.h file is right there in the folder along with all the others. Not sure what is going on.

Thanks
Greg
Could you please tell me what TeensyDuino version you are using?
BTW you are compiling microSoundRecorder and not SimpleAudioLogger
 
Sorry, I had both threads open, and posted to the wrong one. It was late. I'm using the latest Teensyduino, just downloaded it last night. I can move this conversation to the other thread if you prefer.
 
yes let's continue in other thread.
I guess you downloaded from github zip file, extracted into Arduino folder and compiled with TD?
 
Back
Top