diff --git a/tascam_controls/src/alsacontroller.h b/tascam_controls/src/alsacontroller.h index 1d9d6fc..f6f2d88 100644 --- a/tascam_controls/src/alsacontroller.h +++ b/tascam_controls/src/alsacontroller.h @@ -1,27 +1,27 @@ #ifndef ALSACONTROLLER_H #define ALSACONTROLLER_H -#include #include +#include #include -class AlsaController -{ +class AlsaController { public: - AlsaController(const std::vector& target_card_names = {"US-144MKII", "US-144"}); + AlsaController(const std::vector &target_card_names = { + "US-144MKII", "US-144"}); - std::optional getCardId() const; - int getCardNumber() const; - bool isCardFound() const; + std::optional getCardId() const; + int getCardNumber() const; + bool isCardFound() const; - long getControlValue(const std::string& control_name); - bool setControlValue(const std::string& control_name, long value); - std::string readSysfsAttr(const std::string& attr_name); + long getControlValue(const std::string &control_name); + bool setControlValue(const std::string &control_name, long value); + std::string readSysfsAttr(const std::string &attr_name); private: - std::string m_card_id_str; - int m_card_num = -1; - bool m_card_found = false; + std::string m_card_id_str; + int m_card_num = -1; + bool m_card_found = false; }; #endif \ No newline at end of file diff --git a/tascam_controls/src/mainwindow.h b/tascam_controls/src/mainwindow.h index de06e5d..6576c35 100644 --- a/tascam_controls/src/mainwindow.h +++ b/tascam_controls/src/mainwindow.h @@ -1,46 +1,47 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include -#include -#include #include "alsacontroller.h" +#include +#include +#include class QLabel; class QComboBox; class QPushButton; class QDialog; -class MainWindow : public QWidget -{ - Q_OBJECT +class MainWindow : public QWidget { + Q_OBJECT public: - explicit MainWindow(QWidget *parent = nullptr); + explicit MainWindow(QWidget *parent = nullptr); protected: - void paintEvent(QPaintEvent *event) override; + void paintEvent(QPaintEvent *event) override; private: - void initUi(); - void loadDynamicSettings(); - std::pair createControlWidget(const QString& labelText, const QStringList& items); - void updateCombo(QComboBox* combo, const std::string& controlName); + void initUi(); + void loadDynamicSettings(); + std::pair + 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 showAboutDialog(); + void onControlChanged(const std::string &controlName, int index, + QComboBox *combo); + void showAboutDialog(); private: - AlsaController m_alsa; - QPixmap m_background; + AlsaController m_alsa; + QPixmap m_background; - QMap m_infoLabels; - QComboBox* m_capture12Combo; - QComboBox* m_capture34Combo; - QComboBox* m_lineOutCombo; - QComboBox* m_digitalOutCombo; - QDialog* m_aboutDialog; + QMap m_infoLabels; + QComboBox *m_capture12Combo; + QComboBox *m_capture34Combo; + QComboBox *m_lineOutCombo; + QComboBox *m_digitalOutCombo; + QDialog *m_aboutDialog; }; #endif \ No newline at end of file diff --git a/us144mkii.c b/us144mkii.c index 1e10b88..cfeb4b9 100644 --- a/us144mkii.c +++ b/us144mkii.c @@ -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, diff --git a/us144mkii.h b/us144mkii.h index c061963..5f07b73 100644 --- a/us144mkii.h +++ b/us144mkii.h @@ -5,9 +5,9 @@ #define __US144MKII_H #include +#include #include #include -#include #include #include #include @@ -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; diff --git a/us144mkii_capture.c b/us144mkii_capture.c index 40a8f85..30a5e58 100644 --- a/us144mkii_capture.c +++ b/us144mkii_capture.c @@ -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); } - diff --git a/us144mkii_midi.c b/us144mkii_midi.c index 907ad61..f54a8a7 100644 --- a/us144mkii_midi.c +++ b/us144mkii_midi.c @@ -49,7 +49,7 @@ static void tascam_midi_in_work_handler(struct work_struct *work) { } else { /* Data byte */ if (tascam->midi_running_status != 0) snd_rawmidi_receive(tascam->midi_in_substream, - &tascam->midi_running_status, 1); + &tascam->midi_running_status, 1); } /* Submit valid MIDI bytes one by one */ diff --git a/us144mkii_pcm.c b/us144mkii_pcm.c index 1703c7b..52bbd4e 100644 --- a/us144mkii_pcm.c +++ b/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); } } diff --git a/us144mkii_playback.c b/us144mkii_playback.c index 5440112..299d9ee 100644 --- a/us144mkii_playback.c +++ b/us144mkii_playback.c @@ -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; } @@ -161,7 +158,7 @@ void playback_urb_complete(struct urb *urb) { struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; unsigned long flags; - + size_t total_bytes_for_urb = 0; snd_pcm_uframes_t offset_frames; snd_pcm_uframes_t frames_to_copy; @@ -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); } -