On 2008-02-25 14:10, Eric Blossom wrote:
> The code doesn't support S24_3LE because when we wrote it, we didn't
> have any cards that used that format, and it wasn't obvious (to me)
> exactly how the format was represented. It would be great if you
> could sort this out and submit a patch with the fix.

Alright, I sort of got it to work, I'm at least pretty sure about the
format of S24_3LE. I attached the code (just the work_s24_2x1 function
with lots of comments) to this email, if you want to take a look. There
might be a better way to do this, but so far I couldn't think of
anything.

I'm still having a problem with it though and I need help to sort it
out. Most of the time I get buffer overruns from
audio_alsa_source::read_buffer(). The function I wrote seems to work,
this morning I got a clean signal from my sound card (24-bit, 96kHz),
but when I ran the same code later (after some experiments) it produced
buffer overruns again.

Alsa reference [1] says:
> The overrun can happen when an application does not take new captured
> samples in time from alsa-lib.

Is it a speed-issue, is some buffer too small?
What am I doing wrong?

Thank you!
Matt

[1]
http://howto.gp.mines.edu/local-apps/alsa-lib-devel-1.0.14/doxygen/html/pcm.html#pcm_errors

-- 
Mathis Richter <[EMAIL PROTECTED]>
GnuPG Fingerprint: 5069 3C27 0178 D542 DFB4 04F6 29BD 9EF2 1BE0 DDF6

/*
 * Work function that deals with float to S24 conversion
 */
int
audio_alsa_source::work_s24_2x1 (int noutput_items,
                             gr_vector_const_void_star &input_items,
                             gr_vector_void_star &output_items)
{
	typedef gr_int32	sample_t;	// the type of samples we're creating
	static const int NBITS = 24;		// # of bits in a sample

	unsigned int nchan = output_items.size ();
	float **out = (float **) &output_items[0];
	unsigned char *buf = (unsigned char *) d_buffer;

	assert(nchan == 1);

	int bi;

	// actually using 24 bits instead of 32
	unsigned int sizeof_frame = d_hw_nchan * (sizeof (sample_t) - 1);
	assert (d_buffer_size_bytes == d_period_size * sizeof_frame);

	// To minimize latency, return at most a single period's worth of samples.
	// [We could also read the first one in a blocking mode and subsequent
	//  ones in non-blocking mode, but we'll leave that for later (or never).]

	if (!read_buffer (buf, d_period_size, sizeof_frame))
		return -1;		// No fixing this problem.  Say we're done.

	// process one period of data
	//
	//
	// Every frame will have the following byte format:
	//
	// [ byte1_L | byte2_L | byte3_L | byte1_R | byte2_R | byte3_R ]
	//
	// while byte1 will contain the least significant bits of the 24-bit
	// integer, so the bytes will have to be reassembled in reverse order.
	// Three subsequent bytes represent the 24-bit integer for a channel, the
	// following three bytes will contain the sample of the next channel.
	//
	// The bit that determins the sign of the integer will be the 8th bit from
	// the right in byte3. It will later have to be moved to the 32nd bit
	// in the final integer.
	//
	bi = 0;
	for (unsigned int i = 0; i < d_period_size; i++)
	{
		int t[nchan];

		for (unsigned int chan = 0; chan < 2; chan++)
		{
			// get first byte from buffer and put it into a 32-bit integer	
			// t's bytes will look like this:
			// t = [ empty | empty | empty | byte1 ]
			t[chan] = (buf[bi++]);
	
			// shift the next byte 1 byte to the left so that t's bytes look like this:
			// t = [ empty | empty | byte2 | byte1 ]
			t[chan] = t[chan] | (buf[bi++] << 8);
	
			// shift the next byte 2 bytes to the left
			// t = [empty | byte3 | byte2 | byte1 ]
			t[chan] = t[chan] | (buf[bi++] << 16);
			
			// sign of the integer is at the 24th bit (from the right)
			// shift it to the 32nd bit (from the right)
			int sign = (t[chan] & (1 << 23)) << 8;
			int value;
	
			// if the integer we received is negativ
			// t OR (0111 1111 1000 0000 0000 0000 0000 0000)
			// so that all bits that were still 0 are switched to 1
			if (sign != 0)
				value = (t[chan] | 0x7f800000);

			// if the integer is positive, retain all bit values, but make sure
			// that the one where the 'sign' bit used to be is 0
			// t AND (1111 1111 0111 1111 1111 1111 1111 1111)
			else
				value = (t[chan] & 0xff7fffff);
	
			// combine the value of the integer with its sign
			t[chan] = sign | value;
		}
		
		int a = (t[0] + t[1]) / 2;

		out[0][i] = (float) a * (1.0 / (float) ((1L << (NBITS-1)) - 1));
	}

	return d_period_size;
}

Attachment: signature.asc
Description: Digital signature

_______________________________________________
Discuss-gnuradio mailing list
Discuss-gnuradio@gnu.org
http://lists.gnu.org/mailman/listinfo/discuss-gnuradio

Reply via email to