浏览代码

Merge pull request #307 from UrbanLienert/spdif-24bit

24bit SPDIF output
philippe44 1 年之前
父节点
当前提交
72a8fb2249
共有 1 个文件被更改,包括 90 次插入80 次删除
  1. 90 80
      components/squeezelite/output_i2s.c

+ 90 - 80
components/squeezelite/output_i2s.c

@@ -93,6 +93,9 @@ static void (*pseudo_idle_chain)(uint32_t now);
 #define CONFIG_AMP_GPIO_LEVEL 1
 #define CONFIG_AMP_GPIO_LEVEL 1
 #endif
 #endif
 
 
+#define VUCP24      (0xCC)
+#define VUCP24I   	(0x32)
+
 extern struct outputstate output;
 extern struct outputstate output;
 extern struct buffer *streambuf;
 extern struct buffer *streambuf;
 extern struct buffer *outputbuf;
 extern struct buffer *outputbuf;
@@ -115,6 +118,7 @@ static struct {
 	bool enabled;
 	bool enabled;
 	u8_t *buf;
 	u8_t *buf;
 	size_t count;
 	size_t count;
+	u8_t vucp;
 } spdif;
 } spdif;
 static size_t dma_buf_frames;
 static size_t dma_buf_frames;
 static TaskHandle_t output_i2s_task;
 static TaskHandle_t output_i2s_task;
@@ -130,7 +134,7 @@ static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32
 static void output_thread_i2s(void *arg);
 static void output_thread_i2s(void *arg);
 static void i2s_stats(uint32_t now);
 static void i2s_stats(uint32_t now);
 
 
-static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count);
+static void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count, u8_t *vucp);
 static void (*jack_handler_chain)(bool inserted);
 static void (*jack_handler_chain)(bool inserted);
 
 
 #define I2C_PORT	0
 #define I2C_PORT	0
@@ -542,6 +546,7 @@ static void output_thread_i2s(void *arg) {
 				i2s_stop(CONFIG_I2S_NUM);
 				i2s_stop(CONFIG_I2S_NUM);
 				adac->power(ADAC_STANDBY);
 				adac->power(ADAC_STANDBY);
 				spdif.count = 0;
 				spdif.count = 0;
+				spdif.vucp = VUCP24;
 			}
 			}
 			usleep(100000);
 			usleep(100000);
 			continue;
 			continue;
@@ -617,7 +622,7 @@ static void output_thread_i2s(void *arg) {
 			// need IRAM for speed but can't allocate a FRAME_BLOCK * 16, so process by smaller chunks
 			// need IRAM for speed but can't allocate a FRAME_BLOCK * 16, so process by smaller chunks
 			while (count < oframes) {
 			while (count < oframes) {
 				size_t chunk = min(SPDIF_BLOCK, oframes - count);
 				size_t chunk = min(SPDIF_BLOCK, oframes - count);
-				spdif_convert((ISAMPLE_T*) obuf + count * 2, chunk, (u32_t*) spdif.buf, &spdif.count);              
+				spdif_convert((ISAMPLE_T*) obuf + count * 2, chunk, (u32_t*) spdif.buf, &spdif.count, &spdif.vucp);              
 				i2s_write(CONFIG_I2S_NUM, spdif.buf, chunk * 16, &obytes, portMAX_DELAY);
 				i2s_write(CONFIG_I2S_NUM, spdif.buf, chunk * 16, &obytes, portMAX_DELAY);
 				bytes += obytes / (16 / BYTES_PER_FRAME);
 				bytes += obytes / (16 / BYTES_PER_FRAME);
 				count += chunk;
 				count += chunk;
@@ -687,42 +692,39 @@ static void i2s_stats(uint32_t now) {
 #define PREAMBLE_M  (0xE2) //11100010
 #define PREAMBLE_M  (0xE2) //11100010
 #define PREAMBLE_W  (0xE4) //11100100
 #define PREAMBLE_W  (0xE4) //11100100
 
 
-#define VUCP   		((0xCC) << 24)
-#define VUCP_MUTE 	((0xD4) << 24)	// To mute PCM, set VUCP = invalid.
-
-static const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least significant bit first)
-	0xcccc, 0x4ccc, 0x2ccc, 0xaccc, 0x34cc, 0xb4cc, 0xd4cc, 0x54cc,
-	0x32cc, 0xb2cc, 0xd2cc, 0x52cc, 0xcacc, 0x4acc, 0x2acc, 0xaacc,
-	0x334c, 0xb34c, 0xd34c, 0x534c, 0xcb4c, 0x4b4c, 0x2b4c, 0xab4c,
-	0xcd4c, 0x4d4c, 0x2d4c, 0xad4c, 0x354c, 0xb54c, 0xd54c, 0x554c,
-	0x332c, 0xb32c, 0xd32c, 0x532c, 0xcb2c, 0x4b2c, 0x2b2c, 0xab2c,
-	0xcd2c, 0x4d2c, 0x2d2c, 0xad2c, 0x352c, 0xb52c, 0xd52c, 0x552c,
-	0xccac, 0x4cac, 0x2cac, 0xacac, 0x34ac, 0xb4ac, 0xd4ac, 0x54ac,
-	0x32ac, 0xb2ac, 0xd2ac, 0x52ac, 0xcaac, 0x4aac, 0x2aac, 0xaaac,
-	0x3334, 0xb334, 0xd334, 0x5334, 0xcb34, 0x4b34, 0x2b34, 0xab34,
-	0xcd34, 0x4d34, 0x2d34, 0xad34, 0x3534, 0xb534, 0xd534, 0x5534,
-	0xccb4, 0x4cb4, 0x2cb4, 0xacb4, 0x34b4, 0xb4b4, 0xd4b4, 0x54b4,
-	0x32b4, 0xb2b4, 0xd2b4, 0x52b4, 0xcab4, 0x4ab4, 0x2ab4, 0xaab4,
-	0xccd4, 0x4cd4, 0x2cd4, 0xacd4, 0x34d4, 0xb4d4, 0xd4d4, 0x54d4,
-	0x32d4, 0xb2d4, 0xd2d4, 0x52d4, 0xcad4, 0x4ad4, 0x2ad4, 0xaad4,
-	0x3354, 0xb354, 0xd354, 0x5354, 0xcb54, 0x4b54, 0x2b54, 0xab54,
-	0xcd54, 0x4d54, 0x2d54, 0xad54, 0x3554, 0xb554, 0xd554, 0x5554,
-	0x3332, 0xb332, 0xd332, 0x5332, 0xcb32, 0x4b32, 0x2b32, 0xab32,
-	0xcd32, 0x4d32, 0x2d32, 0xad32, 0x3532, 0xb532, 0xd532, 0x5532,
-	0xccb2, 0x4cb2, 0x2cb2, 0xacb2, 0x34b2, 0xb4b2, 0xd4b2, 0x54b2,
-	0x32b2, 0xb2b2, 0xd2b2, 0x52b2, 0xcab2, 0x4ab2, 0x2ab2, 0xaab2,
-	0xccd2, 0x4cd2, 0x2cd2, 0xacd2, 0x34d2, 0xb4d2, 0xd4d2, 0x54d2,
-	0x32d2, 0xb2d2, 0xd2d2, 0x52d2, 0xcad2, 0x4ad2, 0x2ad2, 0xaad2,
-	0x3352, 0xb352, 0xd352, 0x5352, 0xcb52, 0x4b52, 0x2b52, 0xab52,
-	0xcd52, 0x4d52, 0x2d52, 0xad52, 0x3552, 0xb552, 0xd552, 0x5552,
-	0xccca, 0x4cca, 0x2cca, 0xacca, 0x34ca, 0xb4ca, 0xd4ca, 0x54ca,
-	0x32ca, 0xb2ca, 0xd2ca, 0x52ca, 0xcaca, 0x4aca, 0x2aca, 0xaaca,
-	0x334a, 0xb34a, 0xd34a, 0x534a, 0xcb4a, 0x4b4a, 0x2b4a, 0xab4a,
-	0xcd4a, 0x4d4a, 0x2d4a, 0xad4a, 0x354a, 0xb54a, 0xd54a, 0x554a,
-	0x332a, 0xb32a, 0xd32a, 0x532a, 0xcb2a, 0x4b2a, 0x2b2a, 0xab2a,
-	0xcd2a, 0x4d2a, 0x2d2a, 0xad2a, 0x352a, 0xb52a, 0xd52a, 0x552a,
-	0xccaa, 0x4caa, 0x2caa, 0xacaa, 0x34aa, 0xb4aa, 0xd4aa, 0x54aa,
-	0x32aa, 0xb2aa, 0xd2aa, 0x52aa, 0xcaaa, 0x4aaa, 0x2aaa, 0xaaaa
+static const u16_t spdif_bmclookup[256] = {
+	0xcccc, 0xb333, 0xd333, 0xaccc, 0xcb33, 0xb4cc, 0xd4cc, 0xab33, 
+	0xcd33, 0xb2cc, 0xd2cc, 0xad33, 0xcacc, 0xb533, 0xd533, 0xaacc, 
+	0xccb3, 0xb34c, 0xd34c, 0xacb3, 0xcb4c, 0xb4b3, 0xd4b3, 0xab4c, 
+	0xcd4c, 0xb2b3, 0xd2b3, 0xad4c, 0xcab3, 0xb54c, 0xd54c, 0xaab3, 
+	0xccd3, 0xb32c, 0xd32c, 0xacd3, 0xcb2c, 0xb4d3, 0xd4d3, 0xab2c, 
+	0xcd2c, 0xb2d3, 0xd2d3, 0xad2c, 0xcad3, 0xb52c, 0xd52c, 0xaad3, 
+	0xccac, 0xb353, 0xd353, 0xacac, 0xcb53, 0xb4ac, 0xd4ac, 0xab53, 
+	0xcd53, 0xb2ac, 0xd2ac, 0xad53, 0xcaac, 0xb553, 0xd553, 0xaaac, 
+	0xcccb, 0xb334, 0xd334, 0xaccb, 0xcb34, 0xb4cb, 0xd4cb, 0xab34, 
+	0xcd34, 0xb2cb, 0xd2cb, 0xad34, 0xcacb, 0xb534, 0xd534, 0xaacb, 
+	0xccb4, 0xb34b, 0xd34b, 0xacb4, 0xcb4b, 0xb4b4, 0xd4b4, 0xab4b, 
+	0xcd4b, 0xb2b4, 0xd2b4, 0xad4b, 0xcab4, 0xb54b, 0xd54b, 0xaab4, 
+	0xccd4, 0xb32b, 0xd32b, 0xacd4, 0xcb2b, 0xb4d4, 0xd4d4, 0xab2b, 
+	0xcd2b, 0xb2d4, 0xd2d4, 0xad2b, 0xcad4, 0xb52b, 0xd52b, 0xaad4, 
+	0xccab, 0xb354, 0xd354, 0xacab, 0xcb54, 0xb4ab, 0xd4ab, 0xab54, 
+	0xcd54, 0xb2ab, 0xd2ab, 0xad54, 0xcaab, 0xb554, 0xd554, 0xaaab, 
+	0xcccd, 0xb332, 0xd332, 0xaccd, 0xcb32, 0xb4cd, 0xd4cd, 0xab32, 
+	0xcd32, 0xb2cd, 0xd2cd, 0xad32, 0xcacd, 0xb532, 0xd532, 0xaacd, 
+	0xccb2, 0xb34d, 0xd34d, 0xacb2, 0xcb4d, 0xb4b2, 0xd4b2, 0xab4d, 
+	0xcd4d, 0xb2b2, 0xd2b2, 0xad4d, 0xcab2, 0xb54d, 0xd54d, 0xaab2, 
+	0xccd2, 0xb32d, 0xd32d, 0xacd2, 0xcb2d, 0xb4d2, 0xd4d2, 0xab2d, 
+	0xcd2d, 0xb2d2, 0xd2d2, 0xad2d, 0xcad2, 0xb52d, 0xd52d, 0xaad2, 
+	0xccad, 0xb352, 0xd352, 0xacad, 0xcb52, 0xb4ad, 0xd4ad, 0xab52, 
+	0xcd52, 0xb2ad, 0xd2ad, 0xad52, 0xcaad, 0xb552, 0xd552, 0xaaad, 
+	0xccca, 0xb335, 0xd335, 0xacca, 0xcb35, 0xb4ca, 0xd4ca, 0xab35, 
+	0xcd35, 0xb2ca, 0xd2ca, 0xad35, 0xcaca, 0xb535, 0xd535, 0xaaca, 
+	0xccb5, 0xb34a, 0xd34a, 0xacb5, 0xcb4a, 0xb4b5, 0xd4b5, 0xab4a, 
+	0xcd4a, 0xb2b5, 0xd2b5, 0xad4a, 0xcab5, 0xb54a, 0xd54a, 0xaab5, 
+	0xccd5, 0xb32a, 0xd32a, 0xacd5, 0xcb2a, 0xb4d5, 0xd4d5, 0xab2a, 
+	0xcd2a, 0xb2d5, 0xd2d5, 0xad2a, 0xcad5, 0xb52a, 0xd52a, 0xaad5, 
+	0xccaa, 0xb355, 0xd355, 0xacaa, 0xcb55, 0xb4aa, 0xd4aa, 0xab55, 
+	0xcd55, 0xb2aa, 0xd2aa, 0xad55, 0xcaaa, 0xb555, 0xd555, 0xaaaa	
 };
 };
 
 
 /* 
 /* 
@@ -738,62 +740,70 @@ static const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least
  The I2S interface must output first the B/M/W preamble which means that second
  The I2S interface must output first the B/M/W preamble which means that second
  32 bits words must be first and so must be marked right channel. 
  32 bits words must be first and so must be marked right channel. 
 */
 */
-static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
-	register u16_t hi, lo, aux;
+static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count, u8_t *vucp) {
+	register u16_t hi, lo;
+#if BYTES_PER_FRAME == 8
+	register u16_t aux;
+#endif
+	register u8_t vu = *vucp;
 	size_t cnt = *count;
 	size_t cnt = *count;
-	
+
 	while (frames--) {
 	while (frames--) {
 		// start with left channel
 		// start with left channel
 #if BYTES_PER_FRAME == 4		
 #if BYTES_PER_FRAME == 4		
-		hi  = spdif_bmclookup[(u8_t)(*src >> 8)];
-		lo  = spdif_bmclookup[(u8_t) *src++];
-		
-		// invert if last preceeding bit is 1
-		lo ^= ~((s16_t)hi) >> 16;
-		// first 16 bits
-		aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
+		hi = spdif_bmclookup[(u8_t)(*src >> 8)];
+		lo = spdif_bmclookup[(u8_t)*src++];
+		if (lo & 1) hi = ~hi;
+
+		if (++cnt > 191) {
+			*dst++ = (vu << 24) | (PREAMBLE_B << 16) | 0xCCCC;
+			cnt = 0;
+		} else {
+			*dst++ = (vu << 24) | (PREAMBLE_M << 16) | 0xCCCC;
+		}
 #else
 #else
-		hi  = spdif_bmclookup[(u8_t)(*src >> 24)];
-		lo  = spdif_bmclookup[(u8_t)(*src >> 16)];
-		
-		// invert if last preceeding bit is 1
-		lo ^= ~((s16_t)hi) >> 16;
-		// first 16 bits
-		// we use 20 bits samples as we need to force parity
-		aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
-		aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
-		aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
-#endif	
-		
-		// set special preamble every 192 iteration
+		hi = spdif_bmclookup[(u8_t)(*src >> 24)];
+		lo = spdif_bmclookup[(u8_t)(*src >> 16)];
+		aux = spdif_bmclookup[(u8_t)(*src++ >> 8)];
+		if (aux & 1) lo = ~lo;
+		if (lo & 1) hi = ~hi;
+
 		if (++cnt > 191) {
 		if (++cnt > 191) {
-			*dst++ =  VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
+			*dst++ = (vu << 24) | (PREAMBLE_B << 16) | aux;
 			cnt = 0;
 			cnt = 0;
 		} else {
 		} else {
-			*dst++ = VUCP | (PREAMBLE_M << 16) | aux;
-		}     
-        // now write sample's 16 low bits
-        *dst++ = ((u32_t)lo << 16) | hi;		
+			*dst++ = (vu << 24) | (PREAMBLE_M << 16) | aux;
+		}
+#endif
+
+		if (hi & 1) vu = VUCP24I;
+		else vu = VUCP24;
+		*dst++ = ((u32_t)lo << 16) | hi;
 
 
 		// then do right channel, no need to check PREAMBLE_B
 		// then do right channel, no need to check PREAMBLE_B
 #if BYTES_PER_FRAME == 4		
 #if BYTES_PER_FRAME == 4		
-		hi  = spdif_bmclookup[(u8_t)(*src >> 8)];
-		lo  = spdif_bmclookup[(u8_t) *src++];
-		lo ^= ~((s16_t)hi) >> 16;
-		aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
+		hi = spdif_bmclookup[(u8_t)(*src >> 8)];
+		lo = spdif_bmclookup[(u8_t)*src++];
+		if (lo & 1) hi = ~hi;
+
+		*dst++ = (vu << 24) | (PREAMBLE_W << 16) | 0xCCCC;
 #else
 #else
-		hi  = spdif_bmclookup[(u8_t)(*src >> 24)];
-		lo  = spdif_bmclookup[(u8_t)(*src >> 16)];
-		lo ^= ~((s16_t)hi) >> 16;
-		aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
-		aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
-		aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
-#endif	
-		*dst++ = VUCP | (PREAMBLE_W << 16) | aux;
-        *dst++ = ((u32_t)lo << 16) | hi;
+		hi = spdif_bmclookup[(u8_t)(*src >> 24)];
+		lo = spdif_bmclookup[(u8_t)(*src >> 16)];
+		aux = spdif_bmclookup[(u8_t)(*src++ >> 8)];
+		if (aux & 1) lo = ~lo;
+		if (lo & 1) hi = ~hi;
+
+		*dst++ = (vu << 24) | (PREAMBLE_W << 16) | aux;
+#endif
+
+		if (hi & 1) vu = VUCP24I;
+		else vu = VUCP24;
+		*dst++ = ((u32_t)lo << 16) | hi;
 	}
 	}
-	
+
 	*count = cnt;
 	*count = cnt;
+	*vucp = vu;
 }
 }