Browse Source

Add AudioInputUSB - receive USB audio into audio library

main
PaulStoffregen 8 years ago
parent
commit
adca415331
8 changed files with 176 additions and 8 deletions
  1. +1
    -0
      teensy3/AudioStream.cpp
  2. +3
    -1
      teensy3/AudioStream.h
  3. +1
    -0
      teensy3/WProgram.h
  4. +1
    -1
      teensy3/kinetis.h
  5. +130
    -3
      teensy3/usb_audio.cpp
  6. +37
    -0
      teensy3/usb_audio.h
  7. +0
    -3
      teensy3/usb_dev.c
  8. +3
    -0
      teensy3/wiring.h

+ 1
- 0
teensy3/AudioStream.cpp View File

*/ */




#include <string.h> // for memcpy
#include "AudioStream.h" #include "AudioStream.h"





+ 3
- 1
teensy3/AudioStream.h View File

#ifndef AudioStream_h #ifndef AudioStream_h
#define AudioStream_h #define AudioStream_h


#include "Arduino.h"
#include <stdio.h> // for NULL
#include <string.h> // for memcpy
#include "kinetis.h"


#if defined(KINETISK) #if defined(KINETISK)
#define AUDIO_BLOCK_SAMPLES 128 #define AUDIO_BLOCK_SAMPLES 128

+ 1
- 0
teensy3/WProgram.h View File

#include "usb_rawhid.h" #include "usb_rawhid.h"
#include "usb_flightsim.h" #include "usb_flightsim.h"
#include "usb_mtp.h" #include "usb_mtp.h"
#include "usb_audio.h"
#include "usb_undef.h" // do not allow usb_desc.h stuff to leak to user programs #include "usb_undef.h" // do not allow usb_desc.h stuff to leak to user programs


//#include "WCharacter.h" //#include "WCharacter.h"

+ 1
- 1
teensy3/kinetis.h View File





#ifndef NULL #ifndef NULL
#define NULL ((void *)0)
#define NULL (0)
#endif #endif


// Port control and interrupts (PORT) // Port control and interrupts (PORT)

+ 130
- 3
teensy3/usb_audio.cpp View File

* SOFTWARE. * SOFTWARE.
*/ */


#include "usb_dev.h"
#include "usb_audio.h"
#include "HardwareSerial.h" #include "HardwareSerial.h"
#include <string.h> // for memcpy() #include <string.h> // for memcpy()


#ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h #ifdef AUDIO_INTERFACE // defined by usb_dev.h -> usb_desc.h
#if F_CPU >= 20000000 #if F_CPU >= 20000000


uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] __attribute__ ((section(".dmabuffers"), aligned (4)));
uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] __attribute__ ((section(".dmabuffers"), aligned (4)));
bool AudioInputUSB::update_responsibility;
audio_block_t * AudioInputUSB::incoming_left;
audio_block_t * AudioInputUSB::incoming_right;
audio_block_t * AudioInputUSB::ready_left;
audio_block_t * AudioInputUSB::ready_right;
uint16_t AudioInputUSB::incoming_count;

#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4)))
uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR;
uint16_t usb_audio_transmit_buffer[AUDIO_TX_SIZE/2] DMABUFATTR;

void AudioInputUSB::begin(void)
{
incoming_count = 0;
incoming_left = NULL;
incoming_right = NULL;
ready_left = NULL;
ready_right = NULL;
// update_responsibility = update_setup();
// TODO: update responsibility is tough, partly because the USB
// interrupts aren't sychronous to the audio library block size,
// but also because the PC may stop transmitting data, which
// means we no longer get receive callbacks from usb_dev.
update_responsibility = false;
}

static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len)
{
// TODO: optimize...
while (len > 0) {
uint32_t n = *src++;
*left++ = n & 0xFFFF;
*right++ = n >> 16;
len--;
}
}


// Called from the USB interrupt when an isochronous packet arrives // Called from the USB interrupt when an isochronous packet arrives
// we must completely remove it from the receive buffer before returning // we must completely remove it from the receive buffer before returning
// //
void usb_audio_receive_callback(unsigned int len) void usb_audio_receive_callback(unsigned int len)
{ {
unsigned int count, avail;
audio_block_t *left, *right;
const uint32_t *data;

//return;

len >>= 2; // 1 sample = 4 bytes: 2 left, 2 right
data = (const uint32_t *)usb_audio_receive_buffer;

//serial_print("."); //serial_print(".");
//serial_phex(usb_audio_receive_buffer[0]);

count = AudioInputUSB::incoming_count;
left = AudioInputUSB::incoming_left;
right = AudioInputUSB::incoming_right;
if (left == NULL) {
left = AudioStream::allocate();
if (left == NULL) return;
AudioInputUSB::incoming_left = left;
}
if (right == NULL) {
right = AudioStream::allocate();
if (right == NULL) return;
AudioInputUSB::incoming_right = right;
}
while (len > 0) {
avail = AUDIO_BLOCK_SAMPLES - count;
if (len < avail) {
//serial_print(".");
copy_to_buffers(data, left->data + count, right->data + count, len);
AudioInputUSB::incoming_count = count + len;
return;
} else {
//serial_print("^");
copy_to_buffers(data, left->data + count, right->data + count, avail);
data += avail;
len -= avail;
if (AudioInputUSB::ready_left)
AudioStream::release(AudioInputUSB::ready_left);
AudioInputUSB::ready_left = left;
if (AudioInputUSB::ready_right)
AudioStream::release(AudioInputUSB::ready_right);
AudioInputUSB::ready_right = right;
if (AudioInputUSB::update_responsibility) AudioStream::update_all();
left = AudioStream::allocate();
if (left == NULL) {
AudioInputUSB::incoming_left = NULL;
AudioInputUSB::incoming_right = NULL;
AudioInputUSB::incoming_count = 0;
return;
}
right = AudioStream::allocate();
if (right == NULL) {
AudioStream::release(left);
AudioInputUSB::incoming_left = NULL;
AudioInputUSB::incoming_right = NULL;
AudioInputUSB::incoming_count = 0;
return;
}
AudioInputUSB::incoming_left = left;
AudioInputUSB::incoming_right = right;
count = 0;
}
}
AudioInputUSB::incoming_count = count;
} }


void AudioInputUSB::update(void)
{
audio_block_t *left, *right;

__disable_irq();
left = ready_left;
ready_left = NULL;
right = ready_right;
ready_right = NULL;
// TODO: use incoming_count for USB isochronous feedback
__enable_irq();
//if (left && right) {
//serial_print("$");
//} else {
//serial_print("#");
//}
if (left) {
transmit(left, 0);
release(left);
}
if (right) {
transmit(right, 1);
release(right);
}
}




// Called from the USB interrupt when ready to transmit another // Called from the USB interrupt when ready to transmit another
// isochronous packet. If we place data into the transmit buffer, // isochronous packet. If we place data into the transmit buffer,
// the return is the number of bytes. Otherwise, return 0 means // the return is the number of bytes. Otherwise, return 0 means

+ 37
- 0
teensy3/usb_audio.h View File

#ifndef USBaudio_h_
#define USBaudio_h_

#include "usb_desc.h"
#ifdef AUDIO_INTERFACE

#ifdef __cplusplus
extern "C" {
#endif
extern uint16_t usb_audio_receive_buffer[];
extern uint16_t usb_audio_transmit_buffer[];
extern void usb_audio_receive_callback(unsigned int len);
extern unsigned int usb_audio_transmit_callback(void);
#ifdef __cplusplus
}

#include "AudioStream.h"

class AudioInputUSB : public AudioStream
{
public:
AudioInputUSB(void) : AudioStream(0, NULL) { begin(); }
virtual void update(void);
void begin(void);
friend void usb_audio_receive_callback(unsigned int len);
private:
static bool update_responsibility;
static audio_block_t *incoming_left;
static audio_block_t *incoming_right;
static audio_block_t *ready_left;
static audio_block_t *ready_right;
static uint16_t incoming_count;
};

#endif // __cplusplus
#endif // AUDIO_INTERFACE
#endif // USBaudio_h_

+ 0
- 3
teensy3/usb_dev.c View File

} }
} }





} }
USB0_ISTAT = USB_ISTAT_TOKDNE; USB0_ISTAT = USB_ISTAT_TOKDNE;
goto restart; goto restart;

+ 3
- 0
teensy3/wiring.h View File

extern "C"{ extern "C"{
#endif #endif


#ifdef PI
#undef PI
#endif
#define PI 3.1415926535897932384626433832795 #define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398 #define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559 #define TWO_PI 6.283185307179586476925286766559

Loading…
Cancel
Save