feat: Implement dynamic feedback and align URB configuration
This commit is contained in:
parent
d35da0e547
commit
cc31e81f60
|
|
@ -1,14 +1,14 @@
|
|||
#ifndef ALSACONTROLLER_H
|
||||
#define ALSACONTROLLER_H
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class AlsaController
|
||||
{
|
||||
class AlsaController {
|
||||
public:
|
||||
AlsaController(const std::vector<std::string>& target_card_names = {"US-144MKII", "US-144"});
|
||||
AlsaController(const std::vector<std::string> &target_card_names = {
|
||||
"US-144MKII", "US-144"});
|
||||
|
||||
std::optional<std::string> getCardId() const;
|
||||
int getCardNumber() const;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPixmap>
|
||||
#include <QMap>
|
||||
#include "alsacontroller.h"
|
||||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class QComboBox;
|
||||
class QPushButton;
|
||||
class QDialog;
|
||||
|
||||
class MainWindow : public QWidget
|
||||
{
|
||||
class MainWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
@ -24,11 +23,13 @@ protected:
|
|||
private:
|
||||
void initUi();
|
||||
void loadDynamicSettings();
|
||||
std::pair<QWidget*, QComboBox*> createControlWidget(const QString& labelText, const QStringList& items);
|
||||
std::pair<QWidget *, QComboBox *>
|
||||
createControlWidget(const QString &labelText, const QStringList &items);
|
||||
void updateCombo(QComboBox *combo, const std::string &controlName);
|
||||
|
||||
private slots:
|
||||
void onControlChanged(const std::string& controlName, int index, QComboBox* combo);
|
||||
void onControlChanged(const std::string &controlName, int index,
|
||||
QComboBox *combo);
|
||||
void showAboutDialog();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ void tascam_free_urbs(struct tascam_card *tascam) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
kfree(tascam->capture_routing_buffer);
|
||||
tascam->capture_routing_buffer = NULL;
|
||||
kfree(tascam->capture_decode_dst_block);
|
||||
|
|
@ -169,10 +168,10 @@ int tascam_alloc_urbs(struct tascam_card *tascam) {
|
|||
urb->complete = playback_urb_complete;
|
||||
}
|
||||
|
||||
tascam->feedback_urb_alloc_size = FEEDBACK_PACKET_SIZE * MAX_FEEDBACK_PACKETS;
|
||||
tascam->feedback_urb_alloc_size = FEEDBACK_PACKET_SIZE * FEEDBACK_URB_PACKETS;
|
||||
|
||||
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
|
||||
struct urb *f_urb = usb_alloc_urb(MAX_FEEDBACK_PACKETS, GFP_KERNEL);
|
||||
struct urb *f_urb = usb_alloc_urb(FEEDBACK_URB_PACKETS, GFP_KERNEL);
|
||||
|
||||
if (!f_urb)
|
||||
goto error;
|
||||
|
|
@ -264,8 +263,6 @@ int tascam_alloc_urbs(struct tascam_card *tascam) {
|
|||
if (!tascam->capture_decode_dst_block)
|
||||
goto error;
|
||||
|
||||
|
||||
|
||||
tascam->capture_routing_buffer =
|
||||
kmalloc(FRAMES_PER_DECODE_BLOCK * DECODED_CHANNELS_PER_FRAME *
|
||||
DECODED_SAMPLE_SIZE,
|
||||
|
|
|
|||
26
us144mkii.h
26
us144mkii.h
|
|
@ -5,9 +5,9 @@
|
|||
#define __US144MKII_H
|
||||
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/timer.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
|
|
@ -71,10 +71,10 @@ enum tascam_register {
|
|||
#define REG_VAL_ENABLE 0x0101
|
||||
|
||||
/* --- URB Configuration --- */
|
||||
#define NUM_PLAYBACK_URBS 8
|
||||
#define PLAYBACK_URB_PACKETS 4
|
||||
#define NUM_PLAYBACK_URBS 4
|
||||
#define PLAYBACK_URB_PACKETS 8
|
||||
#define NUM_FEEDBACK_URBS 4
|
||||
#define MAX_FEEDBACK_PACKETS 5
|
||||
#define FEEDBACK_URB_PACKETS 1
|
||||
#define FEEDBACK_PACKET_SIZE 3
|
||||
#define NUM_CAPTURE_URBS 8
|
||||
#define CAPTURE_URB_SIZE 512
|
||||
|
|
@ -168,10 +168,7 @@ enum tascam_register {
|
|||
* @feedback_consecutive_errors: Counter for consecutive feedback errors.
|
||||
* @feedback_urb_skip_count: Number of feedback URBs to skip initially for
|
||||
* stabilization.
|
||||
* @feedback_patterns: Pointer to the current feedback patterns based on sample
|
||||
* rate.
|
||||
* @feedback_base_value: Base value for feedback pattern lookup.
|
||||
* @feedback_max_value: Max value for feedback pattern lookup.
|
||||
* @fpo: Holds the state for the dynamic feedback pattern generation.
|
||||
*
|
||||
* @playback_anchor: USB anchor for playback URBs.
|
||||
* @capture_anchor: USB anchor for capture URBs.
|
||||
|
|
@ -203,9 +200,16 @@ struct tascam_card {
|
|||
bool feedback_synced;
|
||||
unsigned int feedback_consecutive_errors;
|
||||
unsigned int feedback_urb_skip_count;
|
||||
const unsigned int (*feedback_patterns)[8];
|
||||
unsigned int feedback_base_value;
|
||||
unsigned int feedback_max_value;
|
||||
|
||||
struct us144mkii_frame_pattern_observer {
|
||||
unsigned int sample_rate_khz;
|
||||
unsigned int base_feedback_value;
|
||||
int feedback_offset;
|
||||
unsigned int full_frame_patterns[5][8];
|
||||
unsigned int current_index;
|
||||
unsigned int previous_index;
|
||||
bool sync_locked;
|
||||
} fpo;
|
||||
|
||||
// MIDI state (frequently accessed in MIDI handlers)
|
||||
atomic_t midi_in_active;
|
||||
|
|
|
|||
|
|
@ -192,10 +192,12 @@ void tascam_capture_work_handler(struct work_struct *work) {
|
|||
if (can_process) {
|
||||
size_t bytes_to_end = CAPTURE_RING_BUFFER_SIZE - read_ptr;
|
||||
if (bytes_to_end >= RAW_BYTES_PER_DECODE_BLOCK) {
|
||||
memcpy(raw_block, tascam->capture_ring_buffer + read_ptr, RAW_BYTES_PER_DECODE_BLOCK);
|
||||
memcpy(raw_block, tascam->capture_ring_buffer + read_ptr,
|
||||
RAW_BYTES_PER_DECODE_BLOCK);
|
||||
} else {
|
||||
memcpy(raw_block, tascam->capture_ring_buffer + read_ptr, bytes_to_end);
|
||||
memcpy(raw_block + bytes_to_end, tascam->capture_ring_buffer, RAW_BYTES_PER_DECODE_BLOCK - bytes_to_end);
|
||||
memcpy(raw_block + bytes_to_end, tascam->capture_ring_buffer,
|
||||
RAW_BYTES_PER_DECODE_BLOCK - bytes_to_end);
|
||||
}
|
||||
tascam->capture_ring_buffer_read_ptr =
|
||||
(read_ptr + RAW_BYTES_PER_DECODE_BLOCK) % CAPTURE_RING_BUFFER_SIZE;
|
||||
|
|
@ -287,4 +289,3 @@ void capture_urb_complete(struct urb *urb) {
|
|||
out:
|
||||
usb_put_urb(urb);
|
||||
}
|
||||
|
||||
|
|
|
|||
120
us144mkii_pcm.c
120
us144mkii_pcm.c
|
|
@ -3,6 +3,68 @@
|
|||
|
||||
#include "us144mkii.h"
|
||||
|
||||
/**
|
||||
* fpoInitPattern() - Generates a packet distribution pattern.
|
||||
* @size: The number of elements in the pattern array (e.g., 8).
|
||||
* @pattern_array: Pointer to the array to be populated.
|
||||
* @initial_value: The base value to initialize each element with.
|
||||
* @target_sum: The desired sum of all elements in the final array.
|
||||
*
|
||||
* This function initializes an array with a base value and then iteratively
|
||||
* adjusts the elements to match a target sum, distributing the difference
|
||||
* as evenly as possible.
|
||||
*/
|
||||
static void fpoInitPattern(unsigned int size, unsigned int *pattern_array,
|
||||
unsigned int initial_value, int target_sum) {
|
||||
unsigned int current_sum;
|
||||
int diff;
|
||||
int abs_diff;
|
||||
unsigned int stride;
|
||||
unsigned int i;
|
||||
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
/* 1. Initialize the array with the base value. */
|
||||
current_sum = 0;
|
||||
for (i = 0; i < size; ++i) {
|
||||
pattern_array[i] = initial_value;
|
||||
}
|
||||
current_sum = size * initial_value;
|
||||
|
||||
/* 2. Iteratively adjust until the sum is correct. */
|
||||
while (current_sum != target_sum) {
|
||||
diff = target_sum - current_sum;
|
||||
abs_diff = (diff > 0) ? diff : -diff;
|
||||
|
||||
if (abs_diff == 0)
|
||||
break;
|
||||
|
||||
/* Calculate the stride to distribute the adjustments. */
|
||||
stride = size / abs_diff;
|
||||
if (stride == 0) {
|
||||
/* This would happen if the difference is larger than the array
|
||||
* size, which indicates a problem. The original code breaks
|
||||
* here.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* Apply the adjustments. */
|
||||
for (i = 0; i < size; i += stride) {
|
||||
if (diff > 0)
|
||||
pattern_array[i]++;
|
||||
else
|
||||
pattern_array[i]--;
|
||||
}
|
||||
|
||||
/* Recalculate the sum for the next iteration. */
|
||||
current_sum = 0;
|
||||
for (i = 0; i < size; ++i)
|
||||
current_sum += pattern_array[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rate-to-Packet Fixing Data
|
||||
*
|
||||
|
|
@ -15,28 +77,6 @@
|
|||
* which helps the driver adjust the packet size dynamically to match the
|
||||
* device's consumption rate.
|
||||
*/
|
||||
static const unsigned int patterns_48khz[5][8] = {{5, 6, 6, 6, 6, 6, 6, 6},
|
||||
{6, 6, 6, 6, 6, 6, 6, 6},
|
||||
{6, 6, 6, 6, 6, 6, 6, 6},
|
||||
{6, 6, 6, 7, 6, 6, 6, 6},
|
||||
{7, 6, 6, 7, 6, 6, 7, 6}};
|
||||
static const unsigned int patterns_96khz[5][8] = {
|
||||
{11, 12, 12, 12, 12, 12, 12, 12},
|
||||
{12, 12, 12, 12, 12, 12, 12, 12},
|
||||
{12, 12, 12, 12, 12, 12, 12, 12},
|
||||
{12, 12, 13, 12, 12, 12, 12, 12},
|
||||
{13, 12, 12, 13, 12, 12, 13, 12}};
|
||||
static const unsigned int patterns_88khz[5][8] = {
|
||||
{10, 11, 11, 11, 11, 11, 11, 11},
|
||||
{11, 11, 11, 11, 11, 11, 11, 11},
|
||||
{11, 11, 11, 11, 11, 11, 11, 11},
|
||||
{11, 11, 12, 11, 11, 11, 11, 11},
|
||||
{12, 11, 11, 12, 11, 11, 12, 11}};
|
||||
static const unsigned int patterns_44khz[5][8] = {{5, 5, 5, 5, 5, 5, 5, 6},
|
||||
{5, 5, 5, 6, 5, 5, 5, 6},
|
||||
{5, 5, 6, 5, 6, 5, 5, 6},
|
||||
{5, 6, 5, 6, 5, 6, 5, 6},
|
||||
{6, 6, 6, 6, 6, 6, 6, 5}};
|
||||
|
||||
const struct snd_pcm_hardware tascam_pcm_hw = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
|
||||
|
|
@ -256,29 +296,19 @@ int tascam_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
return err;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
switch (rate) {
|
||||
case 44100:
|
||||
tascam->feedback_patterns = patterns_44khz;
|
||||
tascam->feedback_base_value = 43;
|
||||
tascam->feedback_max_value = 45;
|
||||
break;
|
||||
case 48000:
|
||||
tascam->feedback_patterns = patterns_48khz;
|
||||
tascam->feedback_base_value = 47;
|
||||
tascam->feedback_max_value = 49;
|
||||
break;
|
||||
case 88200:
|
||||
tascam->feedback_patterns = patterns_88khz;
|
||||
tascam->feedback_base_value = 87;
|
||||
tascam->feedback_max_value = 89;
|
||||
break;
|
||||
case 96000:
|
||||
tascam->feedback_patterns = patterns_96khz;
|
||||
tascam->feedback_base_value = 95;
|
||||
tascam->feedback_max_value = 97;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
tascam->fpo.sample_rate_khz = rate / 1000;
|
||||
tascam->fpo.base_feedback_value = tascam->fpo.sample_rate_khz;
|
||||
tascam->fpo.feedback_offset = 2;
|
||||
tascam->fpo.current_index = 0;
|
||||
tascam->fpo.previous_index = 0;
|
||||
tascam->fpo.sync_locked = false;
|
||||
|
||||
unsigned int initial_value = tascam->fpo.sample_rate_khz / 8;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int target_sum =
|
||||
tascam->fpo.sample_rate_khz - tascam->fpo.feedback_offset + i;
|
||||
fpoInitPattern(8, tascam->fpo.full_frame_patterns[i], initial_value,
|
||||
target_sum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream) {
|
|||
int i, u;
|
||||
size_t nominal_frames_per_packet, nominal_bytes_per_packet;
|
||||
size_t total_bytes_in_urb;
|
||||
unsigned int feedback_packets;
|
||||
|
||||
tascam->driver_playback_pos = 0;
|
||||
tascam->playback_frames_consumed = 0;
|
||||
|
|
@ -70,15 +69,13 @@ static int tascam_playback_prepare(struct snd_pcm_substream *substream) {
|
|||
for (i = 0; i < FEEDBACK_ACCUMULATOR_SIZE; i++)
|
||||
tascam->feedback_accumulator_pattern[i] = nominal_frames_per_packet;
|
||||
|
||||
feedback_packets = 1;
|
||||
|
||||
for (i = 0; i < NUM_FEEDBACK_URBS; i++) {
|
||||
struct urb *f_urb = tascam->feedback_urbs[i];
|
||||
int j;
|
||||
|
||||
f_urb->number_of_packets = feedback_packets;
|
||||
f_urb->transfer_buffer_length = feedback_packets * FEEDBACK_PACKET_SIZE;
|
||||
for (j = 0; j < feedback_packets; j++) {
|
||||
f_urb->number_of_packets = FEEDBACK_URB_PACKETS;
|
||||
f_urb->transfer_buffer_length = FEEDBACK_URB_PACKETS * FEEDBACK_PACKET_SIZE;
|
||||
for (j = 0; j < FEEDBACK_URB_PACKETS; j++) {
|
||||
f_urb->iso_frame_desc[j].offset = j * FEEDBACK_PACKET_SIZE;
|
||||
f_urb->iso_frame_desc[j].length = FEEDBACK_PACKET_SIZE;
|
||||
}
|
||||
|
|
@ -221,10 +218,15 @@ void playback_urb_complete(struct urb *urb) {
|
|||
frames_to_bytes(runtime, runtime->buffer_size - offset_frames);
|
||||
size_t second_chunk_bytes = total_bytes_for_urb - first_chunk_bytes;
|
||||
|
||||
memcpy(dst_buf, runtime->dma_area + frames_to_bytes(runtime, offset_frames), first_chunk_bytes);
|
||||
memcpy(dst_buf + first_chunk_bytes, runtime->dma_area, second_chunk_bytes);
|
||||
memcpy(dst_buf,
|
||||
runtime->dma_area + frames_to_bytes(runtime, offset_frames),
|
||||
first_chunk_bytes);
|
||||
memcpy(dst_buf + first_chunk_bytes, runtime->dma_area,
|
||||
second_chunk_bytes);
|
||||
} else {
|
||||
memcpy(dst_buf, runtime->dma_area + frames_to_bytes(runtime, offset_frames), total_bytes_for_urb);
|
||||
memcpy(dst_buf,
|
||||
runtime->dma_area + frames_to_bytes(runtime, offset_frames),
|
||||
total_bytes_for_urb);
|
||||
}
|
||||
|
||||
/* Apply routing to the contiguous data in our routing buffer */
|
||||
|
|
@ -308,11 +310,20 @@ void feedback_urb_complete(struct urb *urb) {
|
|||
feedback_value =
|
||||
*((u8 *)urb->transfer_buffer + urb->iso_frame_desc[p].offset);
|
||||
|
||||
if (packet_ok && feedback_value >= tascam->feedback_base_value &&
|
||||
feedback_value <= tascam->feedback_max_value) {
|
||||
pattern =
|
||||
tascam
|
||||
->feedback_patterns[feedback_value - tascam->feedback_base_value];
|
||||
if (packet_ok) {
|
||||
int delta = feedback_value - tascam->fpo.base_feedback_value +
|
||||
tascam->fpo.feedback_offset;
|
||||
int pattern_idx;
|
||||
|
||||
if (delta < 0) {
|
||||
pattern_idx = 0; // Clamp to the lowest pattern
|
||||
} else if (delta >= 5) {
|
||||
pattern_idx = 4; // Clamp to the highest pattern
|
||||
} else {
|
||||
pattern_idx = delta;
|
||||
}
|
||||
|
||||
pattern = tascam->fpo.full_frame_patterns[pattern_idx];
|
||||
tascam->feedback_consecutive_errors = 0;
|
||||
int i;
|
||||
|
||||
|
|
@ -418,4 +429,3 @@ unlock_and_continue:
|
|||
out:
|
||||
usb_put_urb(urb);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue