24-bit wav issues vs1005 hiRes

Writing software that inputs and/or outputs audio and performs DSP algorithms such as filters, new codecs or audio effects.
Post Reply
RLee
User
Posts: 18
Joined: Wed 2017-11-22 13:43

24-bit wav issues vs1005 hiRes

Post by RLee » Wed 2018-05-16 18:30

Hi,

I have a recorder that works perfectly at 16-bit but not at 24-bit.

the wav header looks fine for a 10-second file, but the file is only 6.66 seconds long. the first channel consists of noise and the second is appalling. I am using the hi-res vs1005. I am sure I have missed something really obvious but after many hours of experimentation, I still cannot find it :oops: . below is the stripped down c file, the config and my header read from a wav a recorded.

thank you in advance.

Rob

Header file
0 1 2 3 4 5 6 7 8 9 0A 0B 0C 0D 0E 0F
RIFF 5760036 WAVE FMT
16 1 2 96000 576000
6 24 data 5760000

config settings
LCD177
SDSD23 D
UARTIN
AUIADC s 192000 line1_1 line1_3
AUODAC s

Code: Select all

#include <vo_stdio.h>
#include <stdlib.h>
#include <apploader.h> 
#include <kernel.h>   
#include <saturate.h>  
#include <stdio.h>
#include <swap.h>
#include <string.h>
#include <aucommon.h>

#define BUFSIZE 256
#define SAMPLE_RATE 96000
#define SECONDS 10
#define SAMPLES (2*SECONDS*SAMPLE_RATE)
u_int16 buff16[BUFSIZE];

void SetLE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data);
void SetBE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data);
void SetBE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data);
void SetLE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data);

#define RIFF_FILE_SIZE_OFFSET          0x04 //chunkSize 4  Total length of package minus 8 bytes for RIFF
#define RIFF_NUMBER_OF_CHANNELS_OFFSET 0x16 //No Chans 22 
#define RIFF_SAMPLE_RATE_OFFSET        0x18 //sample rate 24
#define RIFF_BYTES_PER_SEC_OFFSET      0x1c //Byte Rate 28 == SampleRate * NumChannels * BitsPerSample/8
#define RIFF_ALIGN_OFFSET              0x20 //Block Align 32 == NumChannels * BitsPerSample/8
#define RIFF_BITS_PER_SAMPLE_OFFSET    0x22 //BitsPerSample 34
#define RIFF_DATA_SIZE_OFFSET          0x28 //SubChunk2Size 40 == NumSamples * NumChannels * BitsPerSample/8

u_int16 riffWavHeader[0x16] = {
  0x5249, 0x4646, 0xFFFF, 0xFFFF, 0x5741, 0x5645, 0x666d, 0x7420,
  0x1000, 0x0000, 0x0100, 0x0200, 0x0077, 0x0100, 0x00ca, 0x0800,
  0x0600, 0x1800, 0x6461, 0x7461, 0xFFFF, 0xFFFF
};

s_int16 SetRiff(s_int32 sampleRate, s_int32 stereoSamples)  {
  u_int32 fileBytes = 44+2*3*stereoSamples; /* Stereo=2, 16 bits=2 */

  SetLE32(riffWavHeader, RIFF_SAMPLE_RATE_OFFSET,     sampleRate);
  SetLE32(riffWavHeader, RIFF_BYTES_PER_SEC_OFFSET,   2*3*sampleRate);
  SetLE16(riffWavHeader, RIFF_ALIGN_OFFSET,           6);
  SetLE16(riffWavHeader, RIFF_BITS_PER_SAMPLE_OFFSET, 24);
  SetLE32(riffWavHeader, RIFF_FILE_SIZE_OFFSET, fileBytes- 8);
  SetLE32(riffWavHeader, RIFF_DATA_SIZE_OFFSET, fileBytes-44);

  return 0;
}

#define MIN(a,b) (((a)<(b))?(a):(b))

ioresult main(char *parameters) {
  FILE *outFile = fopen("d:test.wav","wb");
  s_int32 samplesLeft = SAMPLES;
  s_int32 sampleRate = SAMPLE_RATE;


  if (!outFile) {
    printf("Couldn't open write file\n");
    goto finally;
  }

  ioctl(stdaudioin, IOCTL_AUDIO_SET_IRATE, (void *)(&sampleRate));
  ioctl(stdaudioin, IOCTL_AUDIO_SET_BITS, (void *)16);
  if (ioctl(stdaudioin, IOCTL_AUDIO_SET_INPUT_BUFFER_SIZE, (void *)4096)) {
    printf("Couldn't set input buffer size\n");
    goto finally;
  }

  SetRiff(sampleRate, samplesLeft/2);
  fwrite(&riffWavHeader, sizeof(riffWavHeader), 1, outFile);

  while (samplesLeft) {
    s_int16 i;
    s_int16 samples = (s_int16)MIN(samplesLeft, BUFSIZE);
    u_int16 *bp = buff16;
    fread(buff16, sizeof(buff16[0]), samples, stdaudioin);
    /* Swap bytes because RIFF WAV files are in little-endian mode. */
    for (i=0; i<samples; i++) {
      *bp = Swap16(*bp);
      bp++;
    }
    fwrite(buff16, sizeof(buff16[0]), samples, outFile);
    samplesLeft -= samples;
  }

 finally:
  if (outFile) {
    fclose(outFile);
    outFile = NULL;
  }

  return 0;
}

void SetLE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data) {
  SetBE32(p, byteOffset, Swap32(data));
}
void SetBE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data) {
  u_int16 d1[2];
  d1[0] = (u_int16)(data>>16);
  d1[1] = (u_int16)data;
  MemCopyPackedBigEndian(p, byteOffset, d1, 0, 4);
}
void SetBE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data) {
  u_int16 d1 = data;
  MemCopyPackedBigEndian(p, byteOffset, &d1, 0, 2);
}

void SetLE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data) {
  SetBE16(p, byteOffset, Swap16(data));
}



User avatar
Henrik
VLSI Staff
Posts: 1103
Joined: Tue 2010-06-22 14:10

Re: 24-bit wav issues vs1005 hiRes

Post by Henrik » Thu 2018-05-17 10:18

Hello Rob!

VS1005 audio drivers support 32-bit or 16-bit audio. There is no 24-bit option. If you want to record to a file that is 24 bits, then you need to set the audio drivers to 32-bit mode, then strip and rearrange the bytes to the little-endian format required by RIFF files. Below you will find a highly optimized assembler source for the conversion. Its prototype is:

/* Converts 32-bit interleaved stereo vector in VSDSP byte order
to 24-bit little-endian byte order.
Source and destination may be the same, otherwise they may not overlap. */
void Convert32BitVSDSPTo24BitLE(register __i3 void *d, register __i0 const s_int32 *s, register __d0 u_int16 stereoSamples);
  • d = destination pointer (to 24-bit data).
  • s = source pointer (to 32-bit data). If s and d are same, then the operation is done in-place.
  • stereoSamples = how many 32-bit stereo samples there are in the buffer.
So, using the function goes something like this (incomplete pseudocode untested):

Code: Select all

#define BUFSIZE 256
u_int16 buff16[BUFSIZE];
s_int32 sampleRateAndBits = 48000;

if (bits > 16) sampleRateAndBits = -sampleRateAndBits;
/* abs(sampleRateAndBits) = sampleRate; if (sampleRateAndBits < 0) bits = 32; else bits = 16; */
ioctl(stdaudioin, IOCTL_AUDIO_SET_RATE_AND_BITS, (void *)(&sampleRateAndBits));
ioctl(stdaudioout, IOCTL_AUDIO_SET_RATE_AND_BITS, (void *)(&sampleRateAndBits));

while (1) {
  fread(buff16, sizeof(buff16[0]), BUFSIZE, stdaudioin); /* Read 32-bit samples */
  Convert32BitVSDSPTo24BitLE(buff16, (u_int32 *)buff16, BUFSIZE/4); /* 256-word buffer contains 64 32-bit stereo samples */
  fwrite(buff16, sizeof(buff16[0]), BUFSIZE*3/4, stdaudioout); /* Write 32-bit little-endian data */
}
Name the following file for example audiocopy.s, and add it to your project:

Code: Select all

#include <vs1005h.h> // If your project cannot include vs1005h.h, replace with vs1005g.h
#include <vstypes.h>

/*
void Convert32BitVSDSPTo24BitLE(register __i3 void *d, register __i0 const s_int32 *s, register __d0 u_int16 stereoSamples);
*/
	.sect code,Convert32BitVSDSPTo24BitLE
	.export _Convert32BitVSDSPTo24BitLE
_Convert32BitVSDSPTo24BitLE:
	add d0,ones,d0;	ldx (i6)+1,null
	stx a0,(I6)+1;	sty a1,(I6)
	stx d1,(I6)+1;	sty lc,(I6)
	stx b0,(I6)+1;	sty b1,(I6)
	stx c0,(I6)+1;	sty c1,(I6)
	stx le,(I6)+1;	sty ls,(I6)
	
	jns $9
	and a1,null,a1;	stx i2,(I6)+1

	ldc 0xff00,b1
	ldc 0x00ff,b0
	stx b1,(i6);	sty b0,(i6)
	ldc 8,c1

	ldx (i0)+1,a0
	ldc 1,i2
	and a0,b1,c0;	ldy (i6),b1

	loop d0,$1-1
	ldx (i0)+1,b0
	
	and b0,b1,d1;	ldx (i6),b1
	or d1,c0,c0;	ldx (i0)+1,a0
	and b0,b1,c0;	stx c0,(i3)+1
	ashl a,c1,d;	ldx (i0)+2,a0
	or d1,c0,c0;	ldx (i0)-1,b0
	ashl a,c1,d;	stx c0,(i3)+1
	or d1,d0,c0;	ldx (i0)+2,a0
	and a0,b1,c0;	stx c0,(i3)*	; ldy (i6),b1
$1:

$9:
	ldx (I6)-1,null
	ldx (I6)-1,i2
	ldx (I6)-1,le;	ldy (I6),ls
	ldx (I6)-1,c0;	ldy (I6),c1
	ldx (I6)-1,b0;	ldy (I6),b1
	ldx (I6)-1,d1;	ldy (I6),lc
	jr
	ldx (I6)-1,a0;	ldy (I6),a1
	
	.end
I would like to add one thing that might be an issue.

Your program may work well with fast SD cards. But there may be an issue. Every once in a while the FAT file system needs to read more FAT entries, then write old ones. At this point the SDSD23 driver needs to flush all its data and there may be a discontinuity at that moment. You can detect such issues with

Code: Select all

u_int32 overflows;
ioctl(stdaudioin, IOCTL_AUDIO_GET_OVERFLOWS, (void *)(&overflows));
If overflows grows, you are losing data.

We have released a hi-res recorder that goes around this issue by writing directly to the SD device, so it never does read or seek operations while recording. Because of this, it updates the FAT file system tables only after actual recording has ended. The example is overtly complex for demonstrating this thing, but you might get the idea what happens there. The source code for the VS1005 HiRes Recorder is available at:
viewtopic.php?f=13&t=2210

Kind regards,
- Henrik
Good signatures never die. They just fade away.

RLee
User
Posts: 18
Joined: Wed 2017-11-22 13:43

Re: 24-bit wav issues vs1005 hiRes

Post by RLee » Thu 2018-05-17 15:36

Thank you Henrik,

That makes sense. Before I start sorting it out into 24-bit I thought about ensuring that I can record in 32-bit first. Now the sound quality on both channels is great, but the file length is half what I am programming it to be. I think I have had changed attributes, and again the header is correctly showing the file size but for whatever reason, it is recording at twice the speed required. I was hoping that you could look at the attahced code to see if you spot anything glaringly obvious.

Additionally I am using the hi res board and it is brilliant. I am looking forward to implementing it with the 8 x sd card board.

Code: Select all

#include <vo_stdio.h>
#include <stdlib.h>
#include <apploader.h> 
#include <kernel.h>   
#include <saturate.h>  
#include <stdio.h>
#include <swap.h>
#include <string.h>
#include <aucommon.h>

#define BUFSIZE 256
#define SAMPLE_RATE 48000
#define SECONDS 10
#define SAMPLES (2*SECONDS*SAMPLE_RATE)
u_int16 buff16[BUFSIZE];

void SetLE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data);
void SetBE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data);
void SetBE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data);
void SetLE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data);

#define RIFF_FILE_SIZE_OFFSET          0x04 //chunkSize 4  Total length of package minus 8 bytes for RIFF
#define RIFF_NUMBER_OF_CHANNELS_OFFSET 0x16 //No Chans 22 
#define RIFF_SAMPLE_RATE_OFFSET        0x18 //sample rate 24
#define RIFF_BYTES_PER_SEC_OFFSET      0x1c //Byte Rate 28 == SampleRate * NumChannels * BitsPerSample/8
#define RIFF_ALIGN_OFFSET              0x20 //Block Align 32 == NumChannels * BitsPerSample/8
#define RIFF_BITS_PER_SAMPLE_OFFSET    0x22 //BitsPerSample 34
#define RIFF_DATA_SIZE_OFFSET          0x28 //SubChunk2Size 40 == NumSamples * NumChannels * BitsPerSample/8

u_int16 riffWavHeader[0x16] = {
  0x5249, 0x4646, 0xFFFF, 0xFFFF, 0x5741, 0x5645, 0x666d, 0x7420,
  0x1000, 0x0000, 0x0100, 0x0200, 0x0077, 0x0100, 0x00ca, 0x0800,
  0x0600, 0x1800, 0x6461, 0x7461, 0xFFFF, 0xFFFF
};

s_int16 SetRiff(s_int32 sampleRate, s_int32 stereoSamples)  {
  u_int32 fileBytes = 44+4*2*stereoSamples; /* Stereo=2, 16 bits=2 */

  SetLE32(riffWavHeader, RIFF_SAMPLE_RATE_OFFSET,     sampleRate);
  SetLE32(riffWavHeader, RIFF_BYTES_PER_SEC_OFFSET,   2*4*sampleRate);
  SetLE16(riffWavHeader, RIFF_ALIGN_OFFSET,           8);
  SetLE16(riffWavHeader, RIFF_BITS_PER_SAMPLE_OFFSET, 32);
  SetLE32(riffWavHeader, RIFF_FILE_SIZE_OFFSET, fileBytes- 8);
  SetLE32(riffWavHeader, RIFF_DATA_SIZE_OFFSET, fileBytes-44);

  return 0;
}

#define MIN(a,b) (((a)<(b))?(a):(b))

ioresult main(char *parameters) {
  FILE *outFile = fopen("d:test.wav","wb");
  s_int32 samplesLeft = SAMPLES;
  s_int32 sampleRate = SAMPLE_RATE;
printf("%ld\n",samplesLeft);
printf("%ld\n",sampleRate);


  if (!outFile) {
    printf("Couldn't open write file\n");
    goto finally;
  }

  ioctl(stdaudioin, IOCTL_AUDIO_SET_IRATE, (void *)(&sampleRate));
  ioctl(stdaudioin, IOCTL_AUDIO_SET_BITS, (char *)(32));
  if (ioctl(stdaudioin, IOCTL_AUDIO_SET_INPUT_BUFFER_SIZE, (void *)4096)) {
    printf("Couldn't set input buffer size\n");
    goto finally;
  }

  SetRiff(sampleRate, samplesLeft/2);
  fwrite(&riffWavHeader, sizeof(riffWavHeader), 1, outFile);
printf("buffsize %d\n",BUFSIZE);
  while (samplesLeft) {
    s_int16 i;
    s_int16 samples = (s_int16)MIN(samplesLeft, BUFSIZE);
	
    u_int16 *bp = buff16;
    fread(buff16, sizeof(buff16[0]), samples, stdaudioin);
    /* Swap bytes because RIFF WAV files are in little-endian mode. */
    for (i=0; i<samples; i++) {
      *bp = Swap16(*bp);
      bp++;
    }
//printf("%ld\n",buff16);
    fwrite(buff16, sizeof(buff16[0]), samples, outFile);

    samplesLeft -= samples;
      }

 finally:
  if (outFile) {
  printf("Done\n");
    fclose(outFile);
    outFile = NULL;
  }

  return 0;
}

void SetLE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data) {
  SetBE32(p, byteOffset, Swap32(data));
}
void SetBE32(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int32 __reg_b data) {
  u_int16 d1[2];
  d1[0] = (u_int16)(data>>16);
  d1[1] = (u_int16)data;
  MemCopyPackedBigEndian(p, byteOffset, d1, 0, 4);
}
void SetBE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data) {
  u_int16 d1 = data;
  MemCopyPackedBigEndian(p, byteOffset, &d1, 0, 2);
}

void SetLE16(register __i0 u_int16 *p, register u_int16 __a0 byteOffset, register u_int16 __b0 data) {
  SetBE16(p, byteOffset, Swap16(data));
}



RLee
User
Posts: 18
Joined: Wed 2017-11-22 13:43

Re: 24-bit wav issues vs1005 hiRes

Post by RLee » Fri 2018-05-18 10:19

Hello again Henrick

I found a dirty little solution to the problem. It is not elegant and I am not really sure why I have to do it, but it works.

For anyone that cares is below. Currently recording 2 channels at 192kHz and 32 bit without dropping samples. I am so impressed with the Hi-Res chip.

Code: Select all

  SetRiff(sampleRate, samplesLeft/2);
  
  samplesLeft = samplesLeft* 2; //Samples Left (BitRate/16);
  fwrite(&riffWavHeader, sizeof(riffWavHeader), 1, outFile);

  while (samplesLeft) {
Rob

RLee
User
Posts: 18
Joined: Wed 2017-11-22 13:43

Re: 24-bit wav issues vs1005 hiRes

Post by RLee » Tue 2018-05-22 11:54

The 24-bit conversion worked a charm once I had figured out what to do with the assembly file and fundamentally removed the code that swapped it to little endian before the conversion tried to do the same thing.

Thank you very much for all your help.

Post Reply