Exporting RAW to a CS4334 DAC [CLOSED]

I’m building a custom tablet computer from scratch. I’m currently implementing a Cirrus Logic CS4334 DAC, which attaches to our Altera FPGA via I2S.

A datasheet for the CS4334 can be had here. https://www.cirrus.com/en/pubs/proDatasheet/CS4334-5-8-9_F6.pdf

I’m planning on running it at Stereo 44.1khz at 16-bit. The DAC takes two’s complement serial audio data with MSB first.

My intention to test this is to use audacity to generate some audio, and then export using RAW (header-less) signed 16-bit and then send that data verbatim to the DAC.

My concern is about data format compatibility.

I really don’t know much about audio, but I’m learning now…

Would the data exported be little-endian? MSB?

Given 16-bit signed, is it stored as two’s complement?

Are the first 16-bits the left channel of the first sample, the next 16-bits the right channel?

Does anyone have familiarity with using hardware DACs?

I hope this made it in the right forum.

Thanks
Keith

On Linux, exporting RAW signed 16-bit PCM data is little endian. I don’t know if that’s the same on other platforms. Time to get your Hex editor out I think :wink:
To check the data sample values within a track in Audacity, there is the “Sample Data Export” tool: http://manual.audacityteam.org/o/man/sample_data_export.html

For testing purposes it may be useful to be able to create known sample values. That’s quite easy to do using the “Nyquist Prompt” effect. If you think that might be useful, just ask.

Note that when exporting to an integer format, Audacity applies “dither” by default. Dither will appear in the exported data as low level noise, and that will make your analysis more difficult. To turn off dither, go to “Edit > Preferences > Quality”.

Thanks much for the reply, Steve.

So little endian gets me the BYTE order, but I’ll have to dig in and see if it’s most signficant BIT first, too. Maybe those normally go hand-and-hand, I don’t know.

I love Hex Workshop though. I find myself living in that tool sometimes.

To check the data sample values within a track in Audacity, there is the “Sample Data Export” tool: > Audacity Manual

For testing purposes it may be useful to be able to create known sample values. That’s quite easy to do using the “Nyquist Prompt” effect. If you think that might be useful, just ask.

Yes, that would definitely be useful! Eventually, I might have to trace values all the way through the system.

Note that when exporting to an integer format, Audacity applies “dither” by default. Dither will appear in the exported data as low level noise, and that will make your analysis more difficult. To turn off dither, go to “Edit > Preferences > Quality”.

And thanks for this tidbit – definitely would be a gotcha. However, are the “Signed” 8/16/24/32 PCM encoding integers? Probably not, right? You’d need some way to express the sign in the file. Two’s complement is one method (stealing the high order bit to represent the sign). I can see where the “floats” might be some other type of representation, maybe IEEE 754?

Assuming a signed representation, I guess negative numbers input to the DAC produce an analog waveform instantaneous voltage beneath 0V, and positive numbers above 0V?

Maybe I’ll fill a file with the same value, and then scope out the analog pin to see if I can relate incoming serial audio data and the output waveform. Would be hard to correlate otherwise.

Thanks again

Yes they are.
Audacity works internally with 32-bit floating point sample values (IEEE 754). This is a really nice format for working with audio. Sample values are literally numeric values. A signal level of 0 dB has a peak value of +/- 1.0 (that is the +/- 1.0 vertical scale that is shown by default on the left end of an audio track). Obviously IEEE 754 supports values much greater/smaller than +/- 1.0, which means that audio data within Audacity virtually never “clips”.

The downside of 32-bit float is that it makes file sizes large (double the size of “normal” 16-bit audio) and few media players support the format (though it is quite widely supported in audio editing software).

So “sample values” that lie in the “valid” range below 0 dB lie in the range -1.0 to +1.0.
Obviously it can’t work exactly like that for integer format…

How it works with integer formats is the the available range of integers is “normalized” to a range of +/-1.0.
Example, for signed 16-bit numbers, the range is -32768 to 32767. To “normalize” this range to +/- 1.0, the integer numeric value is divided by 32768 (see note-1 below).
One of the down sides of integer format audio is that, because the range of available values is finite, and all available values are normalized to lie in the range of +/- 1.0, it is impossible to represent values beyond the 0 dB limit - this is why “digital clipping” is inevitable for integer audio if the signal level exceeds 0 dB.

Note-1:
Audacity uses “libsndfile” to handle reading/writing audio data. When libsndfile “normalizes” integer values, it places the “zero bit” at zero and both positive and negative numbers are normalized exactly the same amount, but because there is always an even number of numbers, the maximum possible positive number is always a tiny fraction below 1.0. Other audio I/O libraries may handle this differently. See here for more information: libsndfile : Frequently Asked Questions.


For each of these snippets,

  • Create a new track (Tracks menu > Add New > Mono Track / Stereo Track),
  • Select part of the track,
  • Open the “Nyquist Prompt” effect,
  • Copy and paste the code snippet into the text window of the Nyquist Prompt and apply.

To create a constant level output of +0.4 for the length of the track selection:

(control-srate-abs *sound-srate*
  (const 0.4))

To create a series of sample values, for example 0.3, -0.3, 0.2, -0.2, 0.1, -0.1, 0.0

(setf values #(0.3 -0.3 0.2 -0.2 0.1 -0.1 0.0))
(snd-from-array 0 *sound-srate* values)

To create a square wave at amplitude +/- 0.3 with a frequency of 12.5 Hz for the length of the track selection:

(mult 0.3
      (osc-pulse (hz-to-step 12.5) 0))

To create a series of 1 second signals at levels from -1.0 to +1.0 at amplitude intervals of 0.1:

(simrep (i 20)
        (snd-const (1- (* i 0.05)) i *sound-srate* 1.0))

To create a sine wave with a peak amplitude of 0.6 and a frequency of 1234 Hz:

(mult 0.6 (hzosc 1234))

If you need any other test signals, feel free to ask, or take a look at working with Nyquist: Missing features - Audacity Support (it’s an incredibly powerful tool for research work).

BTW, signed integer PCM audio is almost always “twos compliment”.

Thanks very much for the detail.

Here’s where I’m at currently.

http://www.techtravels.org/?p=1742

I know the Verilog HDL is probably foreign, but I could use some opinion on the audio.

The audio should be 4 seconds of repeating 700hz (generated through audacity tone generated). Sample rate is 8000hz, output RAW as 8-bit signed PCM.

The clip I linked to on the blog post has one out of eight chunks (translates to about 470ms worth) with the correct tone, everything is else, is something different.

Any opinions would be appreciated!

Thanks

The data in the .mif file looks OK from a quick look at the Hex of your source file.

I notice that the spectrum contains frequencies at 300, 500, 700, 900, 1100, 1300, 1500 … 3700, 3900 Hz.
Perhaps a clue in there?

Hey Steve,

I just wanted to say thanks for your help.

I switched the CS4335 DAC, which has a slightly easier interface to talk with.

I outline the problems that I ran into, which included having to switch endian on the Audacity RAW Export and sending the data into the DAC.

http://www.techtravels.org/?p=1752

Didn’t want to leave you hanging. I’ve got plenty more to learn about audio, and if we end up implementing a tone generator, I’ll probably be back! :slight_smile:

Thanks
Keith

Thanks for the update Keith.
Isn’t debugging fun :imp: :smiley:

OK, I’ll mark this topic ‘closed’. When you’re back just start a new topic. Good luck with your project.