Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 41

Thread: Working with New Audio Objects

  1. #1

    Working with New Audio Objects

    Hi All ,

    1. I am new member to Teensy family. I am playing around with existing audio objects created by other member to design custom objects.

    2. I trying to add Serial.print() to update() function but getting some error. " invalid type argument of unary '*' (have 'int32_t {aka long int}') "

    3. If even I insert Serial.print("test") in anywhere in update() function , it also does not show up in serial monitor.

    4. I am attaching my files please guide me.
    Attached Files Attached Files

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,488
    Two problems (I thiink).
    Code:
    Serial.print(*sampleRect);
    1. sampleRect is declared as int32_t so you are trying to print the address of that variable, not its value/content.
    2. Doing a Serial.print in the update() function (which is basically an interrupt routine) is probably going to bog down your code and is a bad thing to do. You are printing *sampleRect 128 times on every entry to update() which is called every 2.9ms. This results in, of course, a total of 44100 prints per second.

    Pete

  3. #3
    Quote Originally Posted by el_supremo View Post
    Two problems (I thiink).
    Code:
    Serial.print(*sampleRect);
    1. sampleRect is declared as int32_t so you are trying to print the address of that variable, not its value/content.
    2. Doing a Serial.print in the update() function (which is basically an interrupt routine) is probably going to bog down your code and is a bad thing to do. You are printing *sampleRect 128 times on every entry to update() which is called every 2.9ms. This results in, of course, a total of 44100 prints per second.

    Pete
    Thanks for reply.
    When I use
    Code:
    Serial.print(sampleRect);
    I don't see any output in serial monitor

  4. #4
    Senior Member houtson's Avatar
    Join Date
    Aug 2015
    Location
    Scotland
    Posts
    135
    Hi @nishant

    Like Pete says, you are going to get a lot of data to serial - it may be overloading it ?

    I usually put a counter in the update loop to dump out 1 in x blocks or 1 in x samples to slow the rate of serial prints.

    Another option is to create a method in your effect that you can call when you want some diagnostics that can be called from your main routine.

    Cheer Paul

  5. #5
    Quote Originally Posted by houtson View Post
    Hi @nishant

    Like Pete says, you are going to get a lot of data to serial - it may be overloading it ?

    I usually put a counter in the update loop to dump out 1 in x blocks or 1 in x samples to slow the rate of serial prints.

    Another option is to create a method in your effect that you can call when you want some diagnostics that can be called from your main routine.

    Cheer Paul
    Thanks @houtson for the advice. But even if a put the serial output like this
    Code:
    void AudioEncoder::update(void)
    {
    	audio_block_t *block;
    	uint32_t i;
    	int32_t sampleRect; //rectified result
        Serial.print("Test"); 
    			
    	// start of processing functions. Could be more elegant based on external
    	// functions but left like this to enable code optimisation later.
    	block = receiveWritable();
    	if (!block) return;
    
    	for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
    
    		sampleRect = block->data[i];
    		if (sampleRect < 0) sampleRect = 0x80000000 - sampleRect;
    		if (sampleRect < 0) sampleRect =  0x7fffffff ;
    	 	block->data[i] = sampleRect;
                Serial.print(i); 
    	}
      
    	transmit(block);
    	release(block);
    }
    Nothing comes up on serial port

  6. #6
    Senior Member houtson's Avatar
    Join Date
    Aug 2015
    Location
    Scotland
    Posts
    135
    Hi @nishant, can you try commenting out or removing your second Serial.print - it will still be flooding serial with 44000 prints a second cheer paul

  7. #7
    Senior Member houtson's Avatar
    Join Date
    Aug 2015
    Location
    Scotland
    Posts
    135
    Hi @nishant, looking again at your codes you seem to be modifying AudioEncoder but you main sketch is calling up a different class - AudioEffectRectifier - is that the problem cheers Paul

  8. #8
    Quote Originally Posted by houtson View Post
    Hi @nishant, looking again at your codes you seem to be modifying AudioEncoder but you main sketch is calling up a different class - AudioEffectRectifier - is that the problem cheers Paul
    Oh I am really sorry, it was a coding issue.It is working now thanks all for guiding me.

  9. #9
    Hi all, I am testing a very basic custom audio object where a just read a audio block and transmit the same.But the in the output is distorted and I am not able to identify why is that. I am sharing the code and audio files.Thanks

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SerialFlash.h>
    #include <C:\Users\mylappie\Documents\Arduino\XOR1\effect_encoder.h>
    
    // GUItool: begin automatically generated code
    
    // GUItool: begin automatically generated code
    AudioInputUSB            usb_In;         //xy=116.26666259765625,322
    AudioEncoder             encoder;        //xy=283.26666259765625,401.26666259765625
    AudioOutputI2S           i2s1;           //xy=651.2666625976562,372
    AudioOutputUSB           usb_Out;        //xy=654.2666625976562,318
    AudioConnection          patchCord1(usb_In, 0, usb_Out, 0);
    AudioConnection          patchCord2(usb_In, 0, i2s1, 0);
    AudioConnection          patchCord3(usb_In, 1, encoder, 0);
    AudioConnection          patchCord4(encoder, 0, usb_Out, 1);
    AudioConnection          patchCord5(encoder, 0, i2s1, 1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=404.26666259765625,214
    // GUItool: end automatically generated code
    
    
    
    void setup() {
      
      Serial.begin(9600);
      while (!Serial) ;
      delay(1000);
       delay(5);  AudioMemory(128);  delay(5);
      
      // Enable the audio shield and set the output volume.
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);
      sgtl5000_1.volume(0.5); //headphone volume
    }
    
    void loop() {
      delay(5);
    }
    Code:
    #include <Arduino.h>
    #include "effect_encoder.h"
    
    void AudioEncoder::update(void)
    {
    	audio_block_t *block;
    	uint32_t i;
    	int32_t sampleRect; //rectified result
    			
    	// start of processing functions. Could be more elegant based on external
    	// functions but left like this to enable code optimisation later.
    	block = receiveWritable();
    	if (!block) return;
    
    	for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
    
    		sampleRect = block->data[i];
        if (i<10){
        Serial.print("Before--+");
        Serial.println(sampleRect);
        }
    	 	block->data[i] = sampleRect;
        if (i<10){
        Serial.print("After + --");
        Serial.println(sampleRect);
         }
    	}
    	transmit(block);
    	release(block);
    }
    Code:
    #ifndef effect_encoder_h_
    #define effect_encoder_h_
    
    #include "Arduino.h"
    #include "AudioStream.h"
    
    class AudioEncoder : public AudioStream
    {
    public:
    	AudioEncoder(void): AudioStream(1, inputQueueArray) {}
     	virtual void update(void);
    	
    private:
    	audio_block_t *inputQueueArray[1];
    };
    
    #endif
    Links to audio files
    http://ge.tt/7PCMEW73

  10. #10
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,488
    Sounds like the Serial.prints in the update() function are interfering with the output.
    Comment the four Serial.print statements and check the audio.

    Pete

  11. #11
    Yes you are correct. But why should Serial.print introduce distortion ?

  12. #12
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,488
    As I mentioned in #2, you are printing 44100 times per second which results in perhaps 176kB/s. The serial buffer is not huge and probably fills up quickly and then (I think) the Serial driver blocks until it has emptied the buffer. This will cause the driver to pause, which causes the audio output to stop briefly which is why the audio sounds so choppy.
    Why do you need to print out every sample? Can't you store, say, a second or two and then print it out in the loop() function?

    Pete

  13. #13
    Senior Member houtson's Avatar
    Join Date
    Aug 2015
    Location
    Scotland
    Posts
    135
    Hi @nishant, I think you're trying to see what's going on inside your custom effect to the actual samples?

    Like Pete says, you are overloading the buffer sending data to it too quickly.

    I've modified you files to add an inspect() method which I'm then calling every second from your loop() to dump one block worth of samples.

    Try that and see if it gives you what you are looking for, cheers, Paul

    Code:
    #include <Audio.h>
    #include <SPI.h>
    #include <SerialFlash.h>
    #include <Wire.h>
    
    #include "effect_encoder.h"
    
    // GUItool: begin automatically generated code
    AudioInputUSB usb_In;    // xy=116.26666259765625,322
    AudioEncoder encoder;    // xy=283.26666259765625,401.26666259765625
    AudioOutputI2S i2s1;     // xy=651.2666625976562,372
    AudioOutputUSB usb_Out;  // xy=654.2666625976562,318
    AudioConnection patchCord1(usb_In, 0, usb_Out, 0);
    AudioConnection patchCord2(usb_In, 0, i2s1, 0);
    AudioConnection patchCord3(usb_In, 1, encoder, 0);
    AudioConnection patchCord4(encoder, 0, usb_Out, 1);
    AudioConnection patchCord5(encoder, 0, i2s1, 1);
    AudioControlSGTL5000 sgtl5000_1;  // xy=404.26666259765625,214
    // GUItool: end automatically generated code
    
    void setup() {
      Serial.begin(9600);
      while (!Serial)
        ;
      delay(1000);
      delay(5);
      AudioMemory(128);
      delay(5);
    
      // Enable the audio shield and set the output volume.
      sgtl5000_1.enable();
      sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);
      sgtl5000_1.volume(0.5);  // headphone volume
    }
    
    void loop() {
      encoder.inspect();
      delay(1000);
    }


    Code:
    #ifndef effect_encoder_h_
    #define effect_encoder_h_
    
    #include "Arduino.h"
    #include "AudioStream.h"
    
    class AudioEncoder : public AudioStream {
     public:
      AudioEncoder(void) : AudioStream(1, inputQueueArray) {}
      virtual void update(void);
      void inspect(void) { dump_samples = true; };  // dump out one blocks worth of samples
    
     private:
      audio_block_t *inputQueueArray[1];
      boolean dump_samples = false;
    };
    
    #endif
    Code:
    #include "effect_encoder.h"
    
    #include <Arduino.h>
    
    void AudioEncoder::update(void) {
      audio_block_t *block;
      uint32_t i;
      int32_t sampleRect;  // rectified result
    
      block = receiveWritable();
      if (!block) return;
    
      for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
        sampleRect = block->data[i];
    
        if (dump_samples) Serial.printf("Before:%d - ", sampleRect);
    
        block->data[i] = sampleRect;
    
        if (dump_samples) Serial.printf("After:%d\n", sampleRect);
      }
    
      // re-set to avoid flooding buffer
      if (dump_samples) dump_samples = false;
    
      transmit(block);
      release(block);
    }

  14. #14
    @houtson it works thanks. @el_supremo I want to process 16 Bytes through my update() function in audio object. When I use AudioMemory(16) so
    Code:
    audio_block_t *block ;  
    block = receiveWritable();
    now will block have 128 or 16 samples ? Also how can I just take only 16 Bytes block for processing ? Thanks

  15. #15
    Senior Member
    Join Date
    Jul 2020
    Posts
    469
    Quote Originally Posted by Nishant View Post
    @houtson it works thanks. @el_supremo I want to process 16 Bytes through my update() function in audio object. When I use AudioMemory(16) so
    Code:
    audio_block_t *block ;  
    block = receiveWritable();
    now will block have 128 or 16 samples ? Also how can I just take only 16 Bytes block for processing ? Thanks
    128, you have not changed anything. AudioMemory takes the number of _blocks_ to pre-allocate space for.

    The samples per block is set by this code in AudioStream.h:
    Code:
    #ifndef AUDIO_BLOCK_SAMPLES
    #define AUDIO_BLOCK_SAMPLES  128
    #endif
    
    #ifndef AUDIO_SAMPLE_RATE_EXACT
    #define AUDIO_SAMPLE_RATE_EXACT 44100.0f
    #endif
    So you have to override these.
    Some Audio lib components only work with AUDIO_BLOCK_SAMPLES == 128 (The FFT classes for one example).

  16. #16
    @ MarkT , each value of AUDIO_BLOCK_SAMPLES is 32 Bit Int. I am trying to use block cipher which accepts only byte. How can I modify int to byte ?One thing which comes to my mind is using highByte() and lowByte() to split int in 4 separate bytes. Something like this:

    audio_block_t *block------> Take block->data[0] to block->data[3] -------> Split in 16 bytes using highByte() & lowByte()----> Encrypt block ---> Combine the block ---> transmit block

    and do the same at other end. Is there a better way to do that ? I am using this
    Code:
    #include <Crypto.h>
    #include <AES.h>
    #include <string.h>
    
    struct TestVector
    {
        const char *name;
        byte key[32];
        byte plaintext[16];
        byte ciphertext[16];
    };
    
    // Define the ECB test vectors from the FIPS specification.
    static TestVector const testVectorAES128 = {
        .name        = "AES-128-ECB",
        .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
        .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                        0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
        .ciphertext  = {0x69, 0xC4, 0xE0, 0xD8, 0x6A, 0x7B, 0x04, 0x30,
                        0xD8, 0xCD, 0xB7, 0x80, 0x70, 0xB4, 0xC5, 0x5A}
    };
    static TestVector const testVectorAES192 = {
        .name        = "AES-192-ECB",
        .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17},
        .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                        0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
        .ciphertext  = {0xDD, 0xA9, 0x7C, 0xA4, 0x86, 0x4C, 0xDF, 0xE0,
                        0x6E, 0xAF, 0x70, 0xA0, 0xEC, 0x0D, 0x71, 0x91}
    };
    static TestVector const testVectorAES256 = {
        .name        = "AES-256-ECB",
        .key         = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F},
        .plaintext   = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                        0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
        .ciphertext  = {0x8E, 0xA2, 0xB7, 0xCA, 0x51, 0x67, 0x45, 0xBF,
                        0xEA, 0xFC, 0x49, 0x90, 0x4B, 0x49, 0x60, 0x89}
    };
    
    AESSmall128 aes128;
    AESSmall256 aes256;
    
    byte buffer[16];
    
    void testCipher(BlockCipher *cipher, const struct TestVector *test)
    {
        crypto_feed_watchdog();
        Serial.print(test->name);
        Serial.print(" Encryption ... ");
        cipher->setKey(test->key, cipher->keySize());
        cipher->encryptBlock(buffer, test->plaintext);
        if (memcmp(buffer, test->ciphertext, 16) == 0)
            Serial.println("Passed");
        else
            Serial.println("Failed");
    
        Serial.print(test->name);
        Serial.print(" Decryption ... ");
        cipher->decryptBlock(buffer, test->ciphertext);
        if (memcmp(buffer, test->plaintext, 16) == 0)
            Serial.println("Passed");
        else
            Serial.println("Failed");
    }
    
    void perfCipher(BlockCipher *cipher, const struct TestVector *test)
    {
        unsigned long start;
        unsigned long elapsed;
        int count;
    
        crypto_feed_watchdog();
    
        Serial.print(test->name);
        Serial.print(" Set Key ... ");
        start = micros();
        for (count = 0; count < 10000; ++count) {
            cipher->setKey(test->key, cipher->keySize());
        }
        elapsed = micros() - start;
        Serial.print(elapsed / 10000.0);
        Serial.print("us per operation, ");
        Serial.print((10000.0 * 1000000.0) / elapsed);
        Serial.println(" per second");
    
        Serial.print(test->name);
        Serial.print(" Encrypt ... ");
        start = micros();
        for (count = 0; count < 5000; ++count) {
            cipher->encryptBlock(buffer, buffer);
        }
        elapsed = micros() - start;
        Serial.print(elapsed / (5000.0 * 16.0));
        Serial.print("us per byte, ");
        Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
        Serial.println(" bytes per second");
    
        Serial.print(test->name);
        Serial.print(" Decrypt ... ");
        start = micros();
        for (count = 0; count < 5000; ++count) {
            cipher->decryptBlock(buffer, buffer);
        }
        elapsed = micros() - start;
        Serial.print(elapsed / (5000.0 * 16.0));
        Serial.print("us per byte, ");
        Serial.print((16.0 * 5000.0 * 1000000.0) / elapsed);
        Serial.println(" bytes per second");
    
        Serial.println();
    }
    
    void setup()
    {
        Serial.begin(9600);
    
        Serial.println();
    
        Serial.println("State Sizes:");
        Serial.print("AESSmall128 ... ");
        Serial.println(sizeof(AESSmall128));
        Serial.print("AESSmall256 ... ");
        Serial.println(sizeof(AESSmall256));
        Serial.println();
    
        Serial.println("Test Vectors:");
        testCipher(&aes128, &testVectorAES128);
        testCipher(&aes256, &testVectorAES256);
    
        Serial.println();
    
        Serial.println("Performance Tests:");
        perfCipher(&aes128, &testVectorAES128);
        perfCipher(&aes256, &testVectorAES256);
    }
    
    void loop()
    {
    }
    Last edited by Nishant; 09-27-2020 at 04:51 PM.

  17. #17
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,488
    block->data[0] to block->data[3] is 8 bytes. Each audio sample is an int16_t not 32-bits.

    Pete

  18. #18
    Quote Originally Posted by el_supremo View Post
    block->data[0] to block->data[3] is 8 bytes. Each audio sample is an int16_t not 32-bits.

    Pete
    Thanks for the correction.But any suggestions how can I break and then recombine the int into bytes for processing for AES

  19. #19
    Senior Member
    Join Date
    Jul 2020
    Posts
    469
    Quote Originally Posted by Nishant View Post
    Thanks for the correction.But any suggestions how can I break and then recombine the int into bytes for processing for AES
    AES blocks are 16 byte, default audio lib blocks are 256 byte, so process 16 AES blocks per audio lib block.
    So something along the lines of:
    Code:
    uint8_t * bptr = (uint8_t*) (block->data) ;  // cast pointer type to byte pointer.
    for (int i = 0 ; i < AUDIO_BLOCK_SAMPLES / 8 ; i++)
    {
      uint8_t aes_block [16] ;
      for (int j = 0 ; j < 16 ; j++)
        aes_block [j] = *bptr++ ;  // copy as it might be overwritten by the encryption code
      process_aes (aes_block, .......) ;
      ...
    }
    Although this implicitly assumes an endianness, but the copying loop can be changed to
    provide a different endianness if wanted.

  20. #20
    Quote Originally Posted by MarkT View Post
    AES blocks are 16 byte, default audio lib blocks are 256 byte, so process 16 AES blocks per audio lib block.
    So something along the lines of:
    Code:
    uint8_t * bptr = (uint8_t*) (block->data) ;  // cast pointer type to byte pointer.
    for (int i = 0 ; i < AUDIO_BLOCK_SAMPLES / 8 ; i++)
    {
      uint8_t aes_block [16] ;
      for (int j = 0 ; j < 16 ; j++)
        aes_block [j] = *bptr++ ;  // copy as it might be overwritten by the encryption code
      process_aes (aes_block, .......) ;
      ...
    }
    Although this implicitly assumes an endianness, but the copying loop can be changed to
    provide a different endianness if wanted.
    @MarkT thanks for help, i will work on the code as you suggested. I hope the audio is not delayed or distorted due ptr typecasting

  21. #21
    Senior Member
    Join Date
    Jul 2020
    Posts
    469
    Pointer type casting is compile-time operation, nothing actually happens at runtime, its the same bits.

  22. #22
    Quote Originally Posted by MarkT View Post
    Pointer type casting is compile-time operation, nothing actually happens at runtime, its the same bits.
    Do I need to typecast the encrypted data
    Code:
    uint8_t aes_block [16]
    back to
    Code:
    uint16_t
    before
    Code:
    transmit()
    Last edited by Nishant; 09-29-2020 at 03:26 PM.

  23. #23
    Senior Member
    Join Date
    Jul 2020
    Posts
    469
    My code copies the data out to process it - if you want to alter the original block you need to
    make sure you've got it in write mode to start with, and in that case you can avoid copying and
    just cast the pointer. If you work on the original data you have altered it in place.

    Alternatively you might need to copy out and copy back (say for endianess reasons).

    Just remember type casts like this don't do anything except stop the compiler complaining about
    having different types for the same pointer. Pointer types are entirely an abstraction in the
    language, not a runtime thing.

  24. #24
    Quote Originally Posted by MarkT View Post
    AES blocks are 16 byte, default audio lib blocks are 256 byte, so process 16 AES blocks per audio lib block.
    So something along the lines of:
    Code:
    uint8_t * bptr = (uint8_t*) (block->data) ;  // cast pointer type to byte pointer.
    for (int i = 0 ; i < AUDIO_BLOCK_SAMPLES / 8 ; i++)
    {
      uint8_t aes_block [16] ;
      for (int j = 0 ; j < 16 ; j++)
        aes_block [j] = *bptr++ ;  // copy as it might be overwritten by the encryption code
      process_aes (aes_block, .......) ;
      ...
    }
    Although this implicitly assumes an endianness, but the copying loop can be changed to
    provide a different endianness if wanted.
    @MarkT , how do I combine all 16 blocks of encrypted data into one array before transmitting ?

  25. #25
    Senior Member
    Join Date
    Jul 2020
    Posts
    469
    You may be able to work in-place if using receiveWritable() and the endianness is correct for the algorithm,
    if copying out and back you simply copy back into the writeable audio block for each encryption block.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •