Working with New Audio Objects

Status
Not open for further replies.

Nishant

Member
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.
 

Attachments

  • effect_encoder.cpp
    2.4 KB · Views: 78
  • effect_encoder.h
    1.8 KB · Views: 68
  • mainfile.ino
    1.6 KB · Views: 68
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
 
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
 
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
 
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
    [B]Serial.print("Test")[/B]; 
			
	// 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;
            [B]Serial.print(i);[/B] 
	}
  
	transmit(block);
	release(block);
}

Nothing comes up on serial port
 
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
 
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
 
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.
 
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
 
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
 
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
 
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);
}
 
@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
 
@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).
 
@ 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:
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.
 
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
 
Pointer type casting is compile-time operation, nothing actually happens at runtime, its the same bits.
 
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:
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.
 
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 ?
 
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.
 
Status
Not open for further replies.
Back
Top