All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
To: clemens@ladisch.de, tiwai@suse.de, robin@gareus.org, damien@zamaudio.com
Cc: alsa-devel@alsa-project.org, ffado-devel@lists.sf.net
Subject: [PATCH 11/11] ALSA: digi00x: apply double-oh-three algorism to multiplex PCM samples
Date: Mon, 16 Mar 2015 01:01:09 +0900	[thread overview]
Message-ID: <1426435269-17059-12-git-send-email-o-takashi@sakamocchi.jp> (raw)
In-Reply-To: <1426435269-17059-1-git-send-email-o-takashi@sakamocchi.jp>

Digi 002/003 family uses own way to multiplex PCM samples into data
blocks in CIP payload for received stream, thus AMDTP-conformant
implementation causes noisy sound.

This commit applies double-oh-three algorism, which discovered by Robin
Gareus and Damien Zammit in 2012.

As long as I tested, this patch still has disorder that:
 * 1st PCM channel still causes noise in 2nd PCM channel.
 * At 88.2/96.0kHz, any PCM channels still causes noise in the other PCM
   channels.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/digi00x/digi00x-protocol.c | 113 ++++++++++++++++++++++++++++++
 sound/firewire/digi00x/digi00x-stream.c   |   2 +
 sound/firewire/digi00x/digi00x.h          |   3 +
 3 files changed, 118 insertions(+)

diff --git a/sound/firewire/digi00x/digi00x-protocol.c b/sound/firewire/digi00x/digi00x-protocol.c
index 4dd373d..ac092cb 100644
--- a/sound/firewire/digi00x/digi00x-protocol.c
+++ b/sound/firewire/digi00x/digi00x-protocol.c
@@ -2,12 +2,125 @@
  * digi00x-protocol.c - a part of driver for Digidesign Digi 002/003 family
  *
  * Copyright (c) 2014-2015 Takashi Sakamoto
+ * Copyright (C) 2012 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2012 Damien Zammit <damien@zamaudio.com>
  *
  * Licensed under the terms of the GNU General Public License, version 2.
  */
 
 #include "digi00x.h"
 
+/*
+ * The double-oh-three algorism is invented by Robin Gareus and Damien Zammit
+ * in 2012, with reverse-engineering for Digi 003 Rack.
+ */
+
+struct dot_state {
+	__u8 carry;
+	__u8 idx;
+	unsigned int off;
+};
+
+#define BYTE_PER_SAMPLE (4)
+#define MAGIC_DOT_BYTE (2)
+
+#define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE)
+
+/*
+ * double-oh-three look up table
+ *
+ * @param idx index byte (audio-sample data) 0x00..0xff
+ * @param off channel offset shift
+ * @return salt to XOR with given data
+ */
+static const __u8 dot_scrt(const __u8 idx, const unsigned int off)
+{
+	/*
+	 * the length of the added pattern only depends on the lower nibble
+	 * of the last non-zero data
+	 */
+	static const __u8 len[16] = {0, 1, 3, 5, 7, 9, 11, 13, 14,
+				     12, 10, 8, 6, 4, 2, 0};
+
+	/*
+	 * the lower nibble of the salt. Interleaved sequence.
+	 * this is walked backwards according to len[]
+	 */
+	static const __u8 nib[15] = {0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4,
+				     0xc, 0x3, 0xd, 0x2, 0xe, 0x1, 0xf};
+
+	/* circular list for the salt's hi nibble. */
+	static const __u8 hir[15] = {0x0, 0x6, 0xf, 0x8, 0x7, 0x5, 0x3, 0x4,
+				     0xc, 0xd, 0xe, 0x1, 0x2, 0xb, 0xa};
+
+	/*
+	 * start offset for upper nibble mapping.
+	 * note: 9 is /special/. In the case where the high nibble == 0x9,
+	 * hir[] is not used and - coincidentally - the salt's hi nibble is
+	 * 0x09 regardless of the offset.
+	 */
+	static const __u8 hio[16] = {0, 11, 12, 6, 7, 5, 1, 4,
+				     3, 0x00, 14, 13, 8, 9, 10, 2};
+
+	const __u8 ln = idx & 0xf;
+	const __u8 hn = (idx >> 4) & 0xf;
+	const __u8 hr = (hn == 0x9) ? 0x9 : hir[(hio[hn] + off) % 15];
+
+	if (len[ln] < off)
+		return 0x00;
+
+	return ((nib[14 + off - len[ln]]) | (hr << 4));
+}
+
+static inline void dot_state_reset(struct dot_state *state)
+{
+	state->carry = 0x00;
+	state->idx   = 0x00;
+	state->off   = 0;
+}
+
+static void dot_encode_step(struct dot_state *state, __be32 *const buffer)
+{
+	__u8 * const data = (__u8 *) buffer;
+
+	if (data[MAGIC_DOT_BYTE] != 0x00) {
+		state->off = 0;
+		state->idx = data[MAGIC_DOT_BYTE] ^ state->carry;
+	}
+	data[MAGIC_DOT_BYTE] ^= state->carry;
+	state->carry = dot_scrt(state->idx, ++(state->off));
+}
+
+void snd_dg00x_protocol_write_s32(struct amdtp_stream *s,
+				  struct snd_pcm_substream *pcm,
+				  __be32 *buffer, unsigned int frames)
+{
+	struct snd_pcm_runtime *runtime = pcm->runtime;
+	unsigned int channels, remaining_frames, i, c;
+	const u32 *src;
+	static struct dot_state state;
+
+	channels = s->pcm_channels;
+	src = (void *)runtime->dma_area +
+			frames_to_bytes(runtime, s->pcm_buffer_pointer);
+	remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+	for (i = 0; i < frames; ++i) {
+		dot_state_reset(&state);
+
+		for (c = 0; c < channels; ++c) {
+			buffer[s->pcm_positions[c]] =
+					cpu_to_be32((*src >> 8) | 0x40000000);
+			dot_encode_step(&state, &buffer[s->pcm_positions[c]]);
+			src++;
+		}
+
+		buffer += s->data_block_quadlets;
+		if (--remaining_frames == 0)
+			src = (void *)runtime->dma_area;
+	}
+}
+
 void snd_dg00x_protocol_fill_midi(struct amdtp_stream *s,
 				  __be32 *buffer, unsigned int frames)
 {
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c
index 410b971..bc4c88c 100644
--- a/sound/firewire/digi00x/digi00x-stream.c
+++ b/sound/firewire/digi00x/digi00x-stream.c
@@ -204,6 +204,8 @@ static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
 	dg00x->rx_stream.midi_position = 0;
 	dg00x->tx_stream.midi_position = 0;
 
+	/* Apply doubleOhThree algorism. */
+	dg00x->rx_stream.transfer_samples = snd_dg00x_protocol_write_s32;
 	dg00x->rx_stream.transfer_midi = snd_dg00x_protocol_fill_midi;
 	dg00x->tx_stream.transfer_midi = snd_dg00x_protocol_pull_midi;
 
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index a658f44..07e54fc 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -84,6 +84,9 @@ enum snd_dg00x_optical_mode {
 	SND_DG00X_OPTICAL_MODE_SPDIF,
 };
 
+void snd_dg00x_protocol_write_s32(struct amdtp_stream *s,
+				  struct snd_pcm_substream *pcm,
+				  __be32 *buffer, unsigned int frames);
 void snd_dg00x_protocol_fill_midi(struct amdtp_stream *s,
 				  __be32 *buffer, unsigned int frames);
 void snd_dg00x_protocol_pull_midi(struct amdtp_stream *s,
-- 
2.1.0

  parent reply	other threads:[~2015-03-15 16:01 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-15 16:00 [RFC][PATCH 00/11] digi00x: new driver for Digidesign 002/003 family Takashi Sakamoto
2015-03-15 16:00 ` [PATCH 01/11] ALSA: digi00x: add skelton for Digi 002/003 device driver Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 02/11] ALSA: digi00x: add streaming functionality Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 03/11] ALSA: digi00x: add proc node for clock status Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 04/11] ALSA: digi00x: add PCM functionality Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 05/11] ALSA: digi00x: add MIDI functionality Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 06/11] ALSA: digi00x: add hwdep interface Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 07/11] ALSA: digi00x: support unknown asynchronous message Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 08/11] ALSA: digi00x: support MIDI ports for device control Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 09/11] ALSA: firewire-lib: allows to implement external MIDI callback function Takashi Sakamoto
2015-03-15 16:01 ` [PATCH 10/11] digi00x: improve MIDI capture/playback Takashi Sakamoto
2015-03-15 16:01 ` Takashi Sakamoto [this message]
2015-03-16 11:39   ` [PATCH 11/11] ALSA: digi00x: apply double-oh-three algorism to multiplex PCM samples Damien Zammit
2015-03-16 13:24     ` Takashi Sakamoto
2015-03-16 14:25   ` Robin Gareus
2015-03-16 16:25     ` Takashi Sakamoto
2015-03-16 17:13       ` Robin Gareus
2015-03-16 22:47         ` Takashi Sakamoto
2015-03-17 13:37           ` Robin Gareus
2015-03-17 13:49             ` Damien Zammit
2015-03-18  1:06               ` Takashi Sakamoto
2015-03-19  5:18                 ` Damien Zammit
2015-03-19 13:59                 ` Robin Gareus
2015-03-19 22:46                   ` Takashi Sakamoto
2015-03-19 22:51                     ` Takashi Sakamoto
2015-03-20 12:05                     ` firewire mixer interface -- was " Robin Gareus
2015-03-20 13:00                       ` Clemens Ladisch
2015-03-20 13:25                       ` Takashi Sakamoto
2015-03-20 13:35                         ` Takashi Iwai
2015-03-20 13:51                           ` Takashi Sakamoto
2015-03-20 14:13                             ` Takashi Iwai
2015-03-20 14:45                               ` Takashi Sakamoto
2015-03-20 15:01                                 ` Takashi Iwai
2015-03-21  5:59                                   ` Damien Zammit
2015-03-22  2:55                                     ` Takashi Sakamoto
2015-03-22  5:56                                       ` [FFADO-devel] " Jonathan Woithe
2015-03-24  3:15                                       ` Robin Gareus
2015-03-20 13:55                         ` Damien Zammit
2015-03-20 14:07                           ` Clemens Ladisch
2015-03-22  6:11                       ` [FFADO-devel] " Jonathan Woithe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1426435269-17059-12-git-send-email-o-takashi@sakamocchi.jp \
    --to=o-takashi@sakamocchi.jp \
    --cc=alsa-devel@alsa-project.org \
    --cc=clemens@ladisch.de \
    --cc=damien@zamaudio.com \
    --cc=ffado-devel@lists.sf.net \
    --cc=robin@gareus.org \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.