Sampled Instrument Player with static and monolithic design. All instruments are built-in.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
6.7 KiB

#include <libusb-1.0/libusb.h>
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <malloc.h>
#include <memory.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
// interface 1 altsetting 1 endpoint 01 (out) bits 16 channels 2 mps 192
// interface 2 altsetting 1 endpoint 83 (in) bits 16 channels 2 mps 192
int samples_captured = 0;
int samples_played = 0;
static struct libusb_context *usbctx;
static int omega_timeout = 1000;
int epOUT = 0x01, epIN = 0x83;
void init_usb()
{
libusb_init(&usbctx);
libusb_set_debug(usbctx, 3);
}
struct libusb_device_handle *open_omega()
{
struct libusb_device_handle *handle;
handle = libusb_open_device_with_vid_pid(usbctx, 0x1210, 0x0002);
if (!handle)
{
printf("Lexicon Omega not found after reset.\n");
return NULL;
}
if (libusb_set_configuration(handle, 1))
{
libusb_close(handle);
return NULL;
}
if (libusb_claim_interface(handle, 1))
goto error;
if (libusb_claim_interface(handle, 2))
goto error;
if (libusb_claim_interface(handle, 7))
goto error;
if (libusb_set_interface_alt_setting(handle, 1, 1))
goto error;
if (libusb_set_interface_alt_setting(handle, 2, 1))
goto error;
return handle;
error:
libusb_close(handle);
return NULL;
}
#define EP_CONTROL_UNDEFINED 0
#define SAMPLING_FREQ_CONTROL 1
#define PITCH_CONTROL 2
#define SET_CUR 0x01
#define GET_CUR 0x81
#define SET_MIN 0x02
#define GET_MIN 0x82
#define SET_MAX 0x03
#define GET_MAX 0x83
#define SET_RES 0x04
#define GET_RES 0x84
#define SET_MEM 0x05
#define GET_MEM 0x85
#define GET_STAT 0xFF
int configure_omega(struct libusb_device_handle *h, int sample_rate)
{
uint8_t freq_data[3];
freq_data[0] = sample_rate & 0xFF;
freq_data[1] = (sample_rate & 0xFF00) >> 8;
freq_data[2] = (sample_rate & 0xFF0000) >> 16;
if (libusb_control_transfer(h, 0x22, 0x01, 256, epOUT, freq_data, 3, omega_timeout) != 3)
return -1;
if (libusb_control_transfer(h, 0x22, 0x01, 256, epIN, freq_data, 3, omega_timeout) != 3)
return -1;
// libusb_control_transfer(dev, 0x22, 0x01,
return 0;
}
// 192 bytes = 1ms@48000 (48 samples)
#define NUM_PLAY_BUFS 2
#define PLAY_PACKET_COUNT 2
#define PLAY_PACKET_SIZE 192
static float phase = 0;
static int phase2 = 0;
static int desync = 0;
static int samples_sent = 0;
static int srate = 48000;
void play_callback(struct libusb_transfer *transfer)
{
int i;
//printf("Play Callback! %d %p status %d\n", (int)transfer->length, transfer->buffer, (int)transfer->status);
samples_played += transfer->length / 4;
int nsamps = srate / 1000;
if (desync >= 1000 * transfer->num_iso_packets && nsamps < PLAY_PACKET_SIZE/4)
nsamps++;
// printf("desync = %d nsamps = %d!\n", desync, nsamps);
int tlen = 0;
for (i = 0; i < transfer->num_iso_packets; i++)
{
tlen += transfer->iso_packet_desc[i].actual_length;
if (transfer->iso_packet_desc[i].status)
printf("ISO error: index = %d i = %d status = %d\n", (int)transfer->user_data, i, transfer->iso_packet_desc[i].status);
}
// printf("actual length = %d!\n", tlen);
transfer->length = nsamps * transfer->num_iso_packets * 4;
libusb_set_iso_packet_lengths(transfer, nsamps * 4);
desync += transfer->num_iso_packets * srate;
desync -= tlen / 4 * 1000;
int16_t *data = (int16_t*)transfer->buffer;
for (i = 0; i < transfer->length / 4; i ++)
{
float v = 16000 * sin(phase);
//phase += (phase2 & 4096) ? 0.02 : 0.04;
phase += (phase2 & 16384) ? 0.04: 0.02;
//phase += 0.2 * cos(phase2 / 16384.0);
phase2++;
if (phase > 2 * M_PI)
phase -= 2 * M_PI;
int vi = (int)v;
data[i * 2] = vi;
data[i * 2 + 1] = vi;
}
libusb_submit_transfer(transfer);
}
void play_stuff(struct libusb_device_handle *h, int index)
{
struct libusb_transfer *t;
int i;
int packets = PLAY_PACKET_COUNT;
t = libusb_alloc_transfer(packets);
int tsize = srate * 4 / 1000;
uint8_t *buf = (uint8_t *)malloc(PLAY_PACKET_SIZE*packets);
//int ssf = 0;
for (i = 0; i < tsize * packets; i++)
buf[i] = 0;
libusb_fill_iso_transfer(t, h, epOUT, buf, tsize * packets, packets, play_callback, (void *)index, 20000);
libusb_set_iso_packet_lengths(t, tsize);
libusb_submit_transfer(t);
}
#define NUM_RECORD_BUFS 2
#define NUM_REC_PACKETS 2
#define REC_PACKET_SIZE 192
static uint8_t *record_buffers[NUM_RECORD_BUFS];
// struct libusb_transfer *record_transfers[NUM_RECORD_BUFS];
float filt = 0;
void record_callback(struct libusb_transfer *transfer)
{
int i;
// printf("Record callback! %p index %d len %d\n", transfer, (int)transfer->user_data, transfer->length);
samples_captured += transfer->length / 4;
float avg = 0;
int16_t *bufz = (int16_t*)transfer->buffer;
int items = transfer->length / 4;
for (i = 0; i < items; i ++)
{
int16_t *buf = &bufz[i * 2];
if (fabs(buf[0]) > avg)
avg = fabs(buf[0]);
if (fabs(buf[1]) > avg)
avg = fabs(buf[1]);
}
if (avg)
printf("%12.6f dBFS\r", 6 * log(avg / 32767 / items) / log(2.0));
libusb_submit_transfer(transfer);
}
void record_stuff(struct libusb_device_handle *h, int index)
{
// 0x02
struct libusb_transfer *t;
record_buffers[index] = (uint8_t*)malloc(NUM_REC_PACKETS * REC_PACKET_SIZE);
memset(record_buffers[index], 0, NUM_REC_PACKETS * REC_PACKET_SIZE);
t = libusb_alloc_transfer(NUM_REC_PACKETS);
libusb_fill_iso_transfer(t, h, epIN, record_buffers[index], NUM_REC_PACKETS * REC_PACKET_SIZE, NUM_REC_PACKETS, record_callback, (void *)index, 1000);
libusb_set_iso_packet_lengths(t, REC_PACKET_SIZE);
if (libusb_submit_transfer(t))
goto error;
return;
error:
printf("Record setup failed for index=%d\n", index);
}
void usb_main_loop()
{
struct sched_param p;
p.sched_priority = 10;
sched_setscheduler(0, SCHED_FIFO, &p);
while(1) {
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 100
};
libusb_handle_events_timeout(usbctx, &tv);
}
}
int main(int argc, char *argv[])
{
struct libusb_device_handle *h;
int i;
init_usb();
h = open_omega();
if (!h)
{
printf("Lexicon Omega could not be opened.\n");
return 2;
}
// 10: 4 3 3 - 16 bit
// 30: 2 2 1 2 2 2 1 - 24 bit
// 50: 4 3 3
// 70: 2 2 1 2 2 2 1
printf("Error = %d\n", configure_omega(h, srate));
usleep(1);
for (i = 0; i < NUM_PLAY_BUFS; i++)
play_stuff(h, i);
for (i = 0; i < NUM_RECORD_BUFS; i++)
record_stuff(h, i);
usb_main_loop();
return 0;
}