xref: /haiku/src/tests/add-ons/kernel/drivers/audio/multi_audio_test.cpp (revision 425ac1b60a56f4df7a0e88bd784545c0ec4fa01f)
102b34466SAxel Dörfler /*
202b34466SAxel Dörfler  * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
302b34466SAxel Dörfler  * Distributed under the terms of the MIT License.
402b34466SAxel Dörfler  */
502b34466SAxel Dörfler 
602b34466SAxel Dörfler 
702b34466SAxel Dörfler #include <errno.h>
802b34466SAxel Dörfler #include <stdint.h>
902b34466SAxel Dörfler #include <stdio.h>
1002b34466SAxel Dörfler #include <string.h>
1102b34466SAxel Dörfler #include <unistd.h>
1214981b21SStephan Aßmus #include <math.h>
1302b34466SAxel Dörfler 
1402b34466SAxel Dörfler #include <hmulti_audio.h>
1502b34466SAxel Dörfler 
1602b34466SAxel Dörfler #include "argv.h"
1702b34466SAxel Dörfler 
1802b34466SAxel Dörfler 
1902b34466SAxel Dörfler #define MAX_CONTROLS	128
2002b34466SAxel Dörfler #define MAX_CHANNELS	32
2102b34466SAxel Dörfler #define NUM_BUFFERS		16
2202b34466SAxel Dörfler 
2302b34466SAxel Dörfler const uint32 kSampleRates[] = {
2402b34466SAxel Dörfler 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
2502b34466SAxel Dörfler 	48000, 64000, 88200, 96000, 176400, 192000, 384000, 1536000
2602b34466SAxel Dörfler };
2702b34466SAxel Dörfler const struct {
2802b34466SAxel Dörfler 	uint32	type;
2914981b21SStephan Aßmus 	const char*	name;
3002b34466SAxel Dörfler } kFormats[] = {
3102b34466SAxel Dörfler 	{B_FMT_8BIT_S, "8bit"},
3202b34466SAxel Dörfler 	{B_FMT_8BIT_U, "8bit-unsigned"},
3302b34466SAxel Dörfler 	{B_FMT_16BIT, "16bit"},
3402b34466SAxel Dörfler 	{B_FMT_18BIT, "18bit"},
3502b34466SAxel Dörfler 	{B_FMT_20BIT, "20bit"},
3602b34466SAxel Dörfler 	{B_FMT_24BIT, "24bit"},
3702b34466SAxel Dörfler 	{B_FMT_32BIT, "32bit"},
3802b34466SAxel Dörfler 	{B_FMT_FLOAT, "float"},
3902b34466SAxel Dörfler 	{B_FMT_DOUBLE, "double"}
4002b34466SAxel Dörfler };
4102b34466SAxel Dörfler 
4202b34466SAxel Dörfler 
4302b34466SAxel Dörfler struct cmd_entry {
4414981b21SStephan Aßmus 	const char*	name;
4502b34466SAxel Dörfler 	void		(*func)(int argc, char **argv);
4614981b21SStephan Aßmus 	const char*	help;
4702b34466SAxel Dörfler };
4802b34466SAxel Dörfler 
4902b34466SAxel Dörfler 
5002b34466SAxel Dörfler extern const char* __progname;
5102b34466SAxel Dörfler 
5202b34466SAxel Dörfler static void do_help(int argc, char** argv);
5302b34466SAxel Dörfler 
5402b34466SAxel Dörfler 
5502b34466SAxel Dörfler static int sDevice;
5602b34466SAxel Dörfler static multi_channel_info sChannelInfo[MAX_CHANNELS];
5702b34466SAxel Dörfler static multi_description sDescription;
5802b34466SAxel Dörfler static uint32 sRate = B_SR_48000;
59a409d733SAxel Dörfler static uint32 sFormat = B_FMT_32BIT;
6002b34466SAxel Dörfler static uint32 sEnabledChannels = ~0;
6102b34466SAxel Dörfler 
6202b34466SAxel Dörfler 
6302b34466SAxel Dörfler static uint32
channel_count()6402b34466SAxel Dörfler channel_count()
6502b34466SAxel Dörfler {
6602b34466SAxel Dörfler 	return sDescription.output_channel_count + sDescription.input_channel_count;
6702b34466SAxel Dörfler }
6802b34466SAxel Dörfler 
6902b34466SAxel Dörfler 
7002b34466SAxel Dörfler static void
set_frame(char * frame,uint32 format,float value)7102b34466SAxel Dörfler set_frame(char* frame, uint32 format, float value)
7202b34466SAxel Dörfler {
7302b34466SAxel Dörfler 	switch (format) {
741cf41b6dSAxel Dörfler 		case B_FMT_8BIT_U:
751cf41b6dSAxel Dörfler 			*(uint8*)frame = uint8(value * INT8_MAX) + 128;
761cf41b6dSAxel Dörfler 			break;
771cf41b6dSAxel Dörfler 		case B_FMT_8BIT_S:
781cf41b6dSAxel Dörfler 			*(int8*)frame = int8(value * INT8_MAX);
791cf41b6dSAxel Dörfler 			break;
8002b34466SAxel Dörfler 		case B_FMT_16BIT:
8102b34466SAxel Dörfler 			*(int16*)frame = int16(value * INT16_MAX);
8202b34466SAxel Dörfler 			break;
831cf41b6dSAxel Dörfler 		case B_FMT_18BIT:
841cf41b6dSAxel Dörfler 		case B_FMT_20BIT:
851cf41b6dSAxel Dörfler 		case B_FMT_24BIT:
8602b34466SAxel Dörfler 		case B_FMT_32BIT:
8702b34466SAxel Dörfler 			*(int32*)frame = int32(value * INT32_MAX);
8802b34466SAxel Dörfler 			break;
8902b34466SAxel Dörfler 		default:
9002b34466SAxel Dörfler 			*(float*)frame = value;
9102b34466SAxel Dörfler 			break;
9202b34466SAxel Dörfler 	}
9302b34466SAxel Dörfler }
9402b34466SAxel Dörfler 
9502b34466SAxel Dörfler 
9602b34466SAxel Dörfler static uint32
get_rate(uint32 rateBits)9702b34466SAxel Dörfler get_rate(uint32 rateBits)
9802b34466SAxel Dörfler {
9902b34466SAxel Dörfler 	uint32 rate = 0;
1001cf41b6dSAxel Dörfler 	for (uint32 i = 0; (1UL << i) <= rateBits
1011cf41b6dSAxel Dörfler 			&& i < sizeof(kSampleRates) / sizeof(kSampleRates[0]); i++) {
1021cf41b6dSAxel Dörfler 		if (((1 << i) & rateBits) != 0)
10302b34466SAxel Dörfler 			rate = kSampleRates[i];
10402b34466SAxel Dörfler 	}
10502b34466SAxel Dörfler 
10602b34466SAxel Dörfler 	return rate;
10702b34466SAxel Dörfler }
10802b34466SAxel Dörfler 
10902b34466SAxel Dörfler 
1101cf41b6dSAxel Dörfler static void
print_rates(uint32 rateBits)1111cf41b6dSAxel Dörfler print_rates(uint32 rateBits)
1121cf41b6dSAxel Dörfler {
1131cf41b6dSAxel Dörfler 	for (uint32 i = 0; i < sizeof(kSampleRates) / sizeof(kSampleRates[0]);
1141cf41b6dSAxel Dörfler 			i++) {
1151cf41b6dSAxel Dörfler 		if (((1 << i) & rateBits) != 0)
1161cf41b6dSAxel Dörfler 			printf("  %lu", kSampleRates[i]);
1171cf41b6dSAxel Dörfler 	}
1181cf41b6dSAxel Dörfler 	putchar('\n');
1191cf41b6dSAxel Dörfler }
1201cf41b6dSAxel Dörfler 
1211cf41b6dSAxel Dörfler 
12202b34466SAxel Dörfler static const char*
get_format_name(uint32 format)12302b34466SAxel Dörfler get_format_name(uint32 format)
12402b34466SAxel Dörfler {
12502b34466SAxel Dörfler 	for (uint32 i = 0; i < sizeof(kFormats) / sizeof(kFormats[0]); i++) {
12602b34466SAxel Dörfler 		if (kFormats[i].type == format)
12702b34466SAxel Dörfler 			return kFormats[i].name;
12802b34466SAxel Dörfler 	}
12902b34466SAxel Dörfler 
13002b34466SAxel Dörfler 	return "unknown";
13102b34466SAxel Dörfler }
13202b34466SAxel Dörfler 
13302b34466SAxel Dörfler 
1341cf41b6dSAxel Dörfler static void
print_formats(uint32 formatBits)1351cf41b6dSAxel Dörfler print_formats(uint32 formatBits)
1361cf41b6dSAxel Dörfler {
1371cf41b6dSAxel Dörfler 	for (uint32 i = 0; i < sizeof(kFormats) / sizeof(kFormats[0]); i++) {
1381cf41b6dSAxel Dörfler 		if ((kFormats[i].type & formatBits) != 0)
1391cf41b6dSAxel Dörfler 			printf("  %s", kFormats[i].name);
1401cf41b6dSAxel Dörfler 	}
1411cf41b6dSAxel Dörfler 	putchar('\n');
1421cf41b6dSAxel Dörfler }
1431cf41b6dSAxel Dörfler 
1441cf41b6dSAxel Dörfler 
14502b34466SAxel Dörfler static const char*
get_kind_name(uint32 kind)14602b34466SAxel Dörfler get_kind_name(uint32 kind)
14702b34466SAxel Dörfler {
14802b34466SAxel Dörfler 	switch (kind) {
14902b34466SAxel Dörfler 		case B_MULTI_OUTPUT_CHANNEL:
15002b34466SAxel Dörfler 			return "out";
15102b34466SAxel Dörfler 		case B_MULTI_INPUT_CHANNEL:
15202b34466SAxel Dörfler 			return "in";
15302b34466SAxel Dörfler 		case B_MULTI_OUTPUT_BUS:
15402b34466SAxel Dörfler 			return "bus-out";
15502b34466SAxel Dörfler 		case B_MULTI_INPUT_BUS:
15602b34466SAxel Dörfler 			return "bus-in";
15702b34466SAxel Dörfler 		case B_MULTI_AUX_BUS:
15802b34466SAxel Dörfler 			return "bus-aux";
15902b34466SAxel Dörfler 
16002b34466SAxel Dörfler 		default:
16102b34466SAxel Dörfler 			return "unknown";
16202b34466SAxel Dörfler 	}
16302b34466SAxel Dörfler }
16402b34466SAxel Dörfler 
16502b34466SAxel Dörfler 
16602b34466SAxel Dörfler //	#pragma mark - Commands
16702b34466SAxel Dörfler 
16802b34466SAxel Dörfler 
16902b34466SAxel Dörfler static void
do_rate(int argc,char ** argv)17002b34466SAxel Dörfler do_rate(int argc, char** argv)
17102b34466SAxel Dörfler {
17202b34466SAxel Dörfler 	if (argc > 1) {
17302b34466SAxel Dörfler 		uint32 rate = strtoul(argv[1], NULL, 0);
17402b34466SAxel Dörfler 		uint32 bits = 0;
17502b34466SAxel Dörfler 
17602b34466SAxel Dörfler 		for (uint32 i = 0; i < sizeof(kSampleRates) / sizeof(kSampleRates[0]);
17702b34466SAxel Dörfler 				i++) {
17802b34466SAxel Dörfler 			if (rate == kSampleRates[i])
17902b34466SAxel Dörfler 				bits = 1 << i;
18002b34466SAxel Dörfler 		}
18102b34466SAxel Dörfler 
18202b34466SAxel Dörfler 		if (bits == 0) {
18302b34466SAxel Dörfler 			fprintf(stderr, "Invalid sample rate %ld!\n", rate);
18402b34466SAxel Dörfler 			printf("Valid values are:");
18502b34466SAxel Dörfler 			for (uint32 i = 0;
18602b34466SAxel Dörfler 					i < sizeof(kSampleRates) / sizeof(kSampleRates[0]); i++) {
18702b34466SAxel Dörfler 				printf(" %lu", kSampleRates[i]);
18802b34466SAxel Dörfler 			}
18902b34466SAxel Dörfler 			putchar('\n');
19002b34466SAxel Dörfler 			return;
19102b34466SAxel Dörfler 		}
19202b34466SAxel Dörfler 		sRate = bits;
19302b34466SAxel Dörfler 	}
19402b34466SAxel Dörfler 
19502b34466SAxel Dörfler 	printf("Current sample rate is %lu Hz (0x%lx)\n", get_rate(sRate), sRate);
19602b34466SAxel Dörfler }
19702b34466SAxel Dörfler 
19802b34466SAxel Dörfler 
19902b34466SAxel Dörfler static void
do_format(int argc,char ** argv)20002b34466SAxel Dörfler do_format(int argc, char** argv)
20102b34466SAxel Dörfler {
202a409d733SAxel Dörfler 	int32 i = -1;
203a409d733SAxel Dörfler 	if (argc == 2)
204a409d733SAxel Dörfler 		i = strtoll(argv[1], NULL, 0);
205a409d733SAxel Dörfler 
206a409d733SAxel Dörfler 	if (i < 1 || i > (int32)(sizeof(kFormats) / sizeof(kFormats[0]))) {
207a409d733SAxel Dörfler 		if (argc == 2)
208a409d733SAxel Dörfler 			fprintf(stderr, "Invalid format: %ld\n", i);
209a409d733SAxel Dörfler 
210a409d733SAxel Dörfler 		for (uint32 i = 0; i < sizeof(kFormats) / sizeof(kFormats[0]); i++) {
211a409d733SAxel Dörfler 			printf("[%ld] %s\n", i + 1, kFormats[i].name);
212a409d733SAxel Dörfler 		}
213a409d733SAxel Dörfler 	} else {
214a409d733SAxel Dörfler 		sFormat = kFormats[i - 1].type;
215a409d733SAxel Dörfler 	}
216a409d733SAxel Dörfler 
21702b34466SAxel Dörfler 	printf("Current sample format is %s (0x%lx)\n", get_format_name(sFormat),
21802b34466SAxel Dörfler 		sFormat);
21902b34466SAxel Dörfler }
22002b34466SAxel Dörfler 
22102b34466SAxel Dörfler 
22202b34466SAxel Dörfler static void
do_desc(int argc,char ** argv)22302b34466SAxel Dörfler do_desc(int argc, char** argv)
22402b34466SAxel Dörfler {
22502b34466SAxel Dörfler 	printf("friendly name:\t\t\t%s\n", sDescription.friendly_name);
22602b34466SAxel Dörfler 	printf("vendor:\t\t\t\t%s\n\n", sDescription.vendor_info);
22702b34466SAxel Dörfler 
2281cf41b6dSAxel Dörfler 	printf("output rates:\t\t\t0x%lx\n", sDescription.output_rates);
2291cf41b6dSAxel Dörfler 	print_rates(sDescription.output_rates);
2301cf41b6dSAxel Dörfler 	printf("input rates:\t\t\t0x%lx\n", sDescription.input_rates);
2311cf41b6dSAxel Dörfler 	print_rates(sDescription.input_rates);
23202b34466SAxel Dörfler 	printf("max cont. var. sample rate:\t%.0f\n",
23302b34466SAxel Dörfler 		sDescription.max_cvsr_rate);
23402b34466SAxel Dörfler 	printf("min cont. var. sample rate:\t%.0f\n",
23502b34466SAxel Dörfler 		sDescription.min_cvsr_rate);
23602b34466SAxel Dörfler 	printf("output formats:\t\t\t0x%lx\n", sDescription.output_formats);
2371cf41b6dSAxel Dörfler 	print_formats(sDescription.output_formats);
23802b34466SAxel Dörfler 	printf("input formats:\t\t\t0x%lx\n", sDescription.input_formats);
2391cf41b6dSAxel Dörfler 	print_formats(sDescription.input_formats);
24002b34466SAxel Dörfler 	printf("lock sources:\t\t\t0x%lx\n", sDescription.lock_sources);
24102b34466SAxel Dörfler 	printf("timecode sources:\t\t0x%lx\n", sDescription.timecode_sources);
24202b34466SAxel Dörfler 	printf("interface flags:\t\t0x%lx\n", sDescription.interface_flags);
24302b34466SAxel Dörfler 	printf("control panel string:\t\t\t%s\n", sDescription.control_panel);
24402b34466SAxel Dörfler 
24502b34466SAxel Dörfler 	printf("\nchannels:\n");
24602b34466SAxel Dörfler 	printf("  %ld outputs, %ld inputs\n", sDescription.output_channel_count,
24702b34466SAxel Dörfler 		sDescription.input_channel_count);
24802b34466SAxel Dörfler 	printf("  %ld out busses, %ld in busses\n",
24902b34466SAxel Dörfler 		sDescription.output_bus_channel_count,
25002b34466SAxel Dörfler 		sDescription.input_bus_channel_count);
25102b34466SAxel Dörfler 	printf("\n  ID\tkind\t   designations\tconnectors\n");
25202b34466SAxel Dörfler 
25302b34466SAxel Dörfler 	for (uint32 i = 0 ; i < channel_count(); i++) {
25402b34466SAxel Dörfler 		printf("%4ld\t%-10s 0x%lx\t0x%lx\n", sDescription.channels[i].channel_id,
25502b34466SAxel Dörfler 			get_kind_name(sDescription.channels[i].kind),
25602b34466SAxel Dörfler 			sDescription.channels[i].designations,
25702b34466SAxel Dörfler 			sDescription.channels[i].connectors);
25802b34466SAxel Dörfler 	}
25902b34466SAxel Dörfler }
26002b34466SAxel Dörfler 
26102b34466SAxel Dörfler 
26202b34466SAxel Dörfler static void
do_channels(int argc,char ** argv)26302b34466SAxel Dörfler do_channels(int argc, char** argv)
26402b34466SAxel Dörfler {
265a409d733SAxel Dörfler 	if (argc == 2)
266a409d733SAxel Dörfler 		sEnabledChannels = strtoul(argv[1], NULL, 0);
267a409d733SAxel Dörfler 
26802b34466SAxel Dörfler 	uint32 enabled = ((1 << channel_count()) - 1) & sEnabledChannels;
26902b34466SAxel Dörfler 
27002b34466SAxel Dörfler 	printf("%ld channels:\n  ", channel_count());
27102b34466SAxel Dörfler 	for (uint32 i = 0; i < channel_count(); i++) {
27202b34466SAxel Dörfler 		printf(enabled & 1 ? "x" : "-");
27302b34466SAxel Dörfler 		enabled >>= 1;
27402b34466SAxel Dörfler 	}
27502b34466SAxel Dörfler 	putchar('\n');
27602b34466SAxel Dörfler }
27702b34466SAxel Dörfler 
27802b34466SAxel Dörfler 
27902b34466SAxel Dörfler static void
do_play(int argc,char ** argv)28002b34466SAxel Dörfler do_play(int argc, char** argv)
28102b34466SAxel Dörfler {
282a409d733SAxel Dörfler 	uint32 playMask = 0xffffffff;
283a409d733SAxel Dörfler 	if (argc == 2)
284a409d733SAxel Dörfler 		playMask = strtoul(argv[1], NULL, 0);
285a409d733SAxel Dörfler 
28602b34466SAxel Dörfler 	multi_channel_enable channelEnable;
28702b34466SAxel Dörfler 	uint32 enabled = ((1 << channel_count()) - 1) & sEnabledChannels;
28802b34466SAxel Dörfler 
28902b34466SAxel Dörfler 	channelEnable.enable_bits = (uchar*)&enabled;
29002b34466SAxel Dörfler 	channelEnable.lock_source = B_MULTI_LOCK_INTERNAL;
29102b34466SAxel Dörfler 	if (ioctl(sDevice, B_MULTI_SET_ENABLED_CHANNELS, &channelEnable,
29202b34466SAxel Dörfler 			sizeof(multi_channel_enable)) < B_OK) {
29302b34466SAxel Dörfler 		fprintf(stderr, "Setting enabled channels failed: %s\n",
29402b34466SAxel Dörfler 			strerror(errno));
29502b34466SAxel Dörfler 	}
29602b34466SAxel Dörfler 
29702b34466SAxel Dörfler 	multi_format_info formatInfo;
29802b34466SAxel Dörfler 	formatInfo.info_size = sizeof(multi_format_info);
29902b34466SAxel Dörfler 	formatInfo.output.rate = sRate;
30002b34466SAxel Dörfler 	formatInfo.output.cvsr = 0;
30102b34466SAxel Dörfler 	formatInfo.output.format = sFormat;
30202b34466SAxel Dörfler 	formatInfo.input.rate = formatInfo.output.rate;
30302b34466SAxel Dörfler 	formatInfo.input.cvsr = formatInfo.output.cvsr;
30402b34466SAxel Dörfler 	formatInfo.input.format = formatInfo.output.format;
30502b34466SAxel Dörfler 
30602b34466SAxel Dörfler 	if (ioctl(sDevice, B_MULTI_SET_GLOBAL_FORMAT, &formatInfo,
30702b34466SAxel Dörfler 			sizeof(multi_format_info)) < B_OK) {
30802b34466SAxel Dörfler 		printf("Setting global format failed: %s\n", strerror(errno));
30902b34466SAxel Dörfler 	}
31002b34466SAxel Dörfler 
31102b34466SAxel Dörfler 	if (ioctl(sDevice, B_MULTI_GET_GLOBAL_FORMAT, &formatInfo,
31202b34466SAxel Dörfler 			sizeof(multi_format_info)) < B_OK) {
31302b34466SAxel Dörfler 		printf("Getting global format failed: %s\n", strerror(errno));
31402b34466SAxel Dörfler 	}
31502b34466SAxel Dörfler 
31602b34466SAxel Dörfler 	printf("format %s (0x%lx)\n", get_format_name(formatInfo.output.format),
31702b34466SAxel Dörfler 		formatInfo.output.format);
31802b34466SAxel Dörfler 	printf("sample rate %lu (0x%lx)\n", get_rate(formatInfo.output.rate),
31902b34466SAxel Dörfler 		formatInfo.output.rate);
32002b34466SAxel Dörfler 
32102b34466SAxel Dörfler 	buffer_desc playBuffers[NUM_BUFFERS * MAX_CHANNELS];
32202b34466SAxel Dörfler 	buffer_desc recordBuffers[NUM_BUFFERS * MAX_CHANNELS];
32302b34466SAxel Dörfler 	buffer_desc* playBufferDesc[NUM_BUFFERS];
32402b34466SAxel Dörfler 	buffer_desc* recordBufferDesc[NUM_BUFFERS];
32502b34466SAxel Dörfler 
32602b34466SAxel Dörfler 	for (uint32 i = 0; i < NUM_BUFFERS; i++) {
32702b34466SAxel Dörfler 		playBufferDesc[i] = &playBuffers[i * MAX_CHANNELS];
32802b34466SAxel Dörfler 		recordBufferDesc[i] = &recordBuffers[i * MAX_CHANNELS];
32902b34466SAxel Dörfler 	}
33002b34466SAxel Dörfler 
33102b34466SAxel Dörfler 	multi_buffer_list bufferList;
33202b34466SAxel Dörfler 	bufferList.info_size = sizeof(multi_buffer_list);
33302b34466SAxel Dörfler 	bufferList.request_playback_buffer_size = 0;
33402b34466SAxel Dörfler 	bufferList.request_playback_buffers = NUM_BUFFERS;
33502b34466SAxel Dörfler 	bufferList.request_playback_channels = sDescription.output_channel_count;
33602b34466SAxel Dörfler 	bufferList.playback_buffers = (buffer_desc**)playBufferDesc;
33702b34466SAxel Dörfler 	bufferList.request_record_buffer_size = 0;
33802b34466SAxel Dörfler 	bufferList.request_record_buffers = NUM_BUFFERS;
33902b34466SAxel Dörfler 	bufferList.request_record_channels = sDescription.input_channel_count;
34002b34466SAxel Dörfler 	bufferList.record_buffers = (buffer_desc**)recordBufferDesc;
34102b34466SAxel Dörfler 
34202b34466SAxel Dörfler 	if (ioctl(sDevice, B_MULTI_GET_BUFFERS, &bufferList,
34302b34466SAxel Dörfler 			sizeof(multi_buffer_list)) < B_OK) {
34402b34466SAxel Dörfler 		printf("Getting buffers failed: %s\n", strerror(errno));
34502b34466SAxel Dörfler 		return;
34602b34466SAxel Dörfler 	}
34702b34466SAxel Dörfler 
34802b34466SAxel Dörfler 	printf("playback: buffer count %ld, channels %ld, buffer size %ld\n",
34902b34466SAxel Dörfler 		bufferList.return_playback_buffers, bufferList.return_playback_channels,
35002b34466SAxel Dörfler 		bufferList.return_playback_buffer_size);
351a409d733SAxel Dörfler 	for (int32 channel = 0; channel < bufferList.return_playback_channels;
352a409d733SAxel Dörfler 			channel++) {
353a409d733SAxel Dörfler 		printf("  Channel %ld\n", channel);
354a409d733SAxel Dörfler 		for (int32 i = 0; i < bufferList.return_playback_buffers; i++) {
355a409d733SAxel Dörfler 			printf("    [%ld] buffer %p, stride %ld\n", i,
356a409d733SAxel Dörfler 				bufferList.playback_buffers[i][channel].base,
357a409d733SAxel Dörfler 				bufferList.playback_buffers[i][channel].stride);
358a409d733SAxel Dörfler 		}
359a409d733SAxel Dörfler 	}
360a409d733SAxel Dörfler 
36102b34466SAxel Dörfler 	printf("record: buffer count %ld, channels %ld, buffer size %ld\n",
36202b34466SAxel Dörfler 		bufferList.return_record_buffers, bufferList.return_record_channels,
36302b34466SAxel Dörfler 		bufferList.return_record_buffer_size);
36402b34466SAxel Dörfler 
36502b34466SAxel Dörfler 	multi_buffer_info bufferInfo;
36602b34466SAxel Dörfler 	memset(&bufferInfo, 0, sizeof(multi_buffer_info));
36702b34466SAxel Dörfler 	bufferInfo.info_size = sizeof(multi_buffer_info);
36802b34466SAxel Dörfler 
36902b34466SAxel Dörfler 	bigtime_t startTime = system_time();
370a409d733SAxel Dörfler 	uint32 exchanged = 0;
3711cf41b6dSAxel Dörfler 	int32 cycle = -1;
372a409d733SAxel Dörfler 	uint32 x = 0;
37302b34466SAxel Dörfler 	while (true) {
37402b34466SAxel Dörfler 		if (system_time() - startTime > 1000000LL)
37502b34466SAxel Dörfler 			break;
37602b34466SAxel Dörfler 
37702b34466SAxel Dörfler 		if (ioctl(sDevice, B_MULTI_BUFFER_EXCHANGE, &bufferInfo,
37802b34466SAxel Dörfler 				sizeof(multi_buffer_list)) < B_OK) {
37902b34466SAxel Dörfler 			printf("Getting buffers failed: %s\n", strerror(errno));
380b3c896afSAugustin Cavalier 			continue;
38102b34466SAxel Dörfler 		}
38202b34466SAxel Dörfler 
383a409d733SAxel Dörfler 		// fill buffer with data
384a409d733SAxel Dörfler 
385a409d733SAxel Dörfler 		// Note: hmulti-audio drivers may actually return more than once
386a409d733SAxel Dörfler 		// per buffer...
387a409d733SAxel Dörfler 		if (cycle == bufferInfo.playback_buffer_cycle
388a409d733SAxel Dörfler 			&& bufferList.return_playback_buffers != 1)
389a409d733SAxel Dörfler 			continue;
390a409d733SAxel Dörfler 
391a409d733SAxel Dörfler 		cycle = bufferInfo.playback_buffer_cycle;
392a409d733SAxel Dörfler 
393a409d733SAxel Dörfler 		size_t stride = bufferList.playback_buffers[cycle][0].stride;
394a409d733SAxel Dörfler 		for (int32 channel = 0; channel < bufferList.return_playback_channels;
395a409d733SAxel Dörfler 				channel++) {
396a409d733SAxel Dörfler 			if (((1 << channel) & playMask) == 0)
397a409d733SAxel Dörfler 				continue;
398a409d733SAxel Dörfler 
399a409d733SAxel Dörfler 			char* dest = bufferList.playback_buffers[cycle][channel].base;
400a409d733SAxel Dörfler 			for (uint32 frame = 0;
401a409d733SAxel Dörfler 					frame < bufferList.return_playback_buffer_size; frame++) {
402a409d733SAxel Dörfler 				set_frame(dest, formatInfo.output.format, sin((x + frame) / 32.0));
403a409d733SAxel Dörfler 				dest += stride;
40402b34466SAxel Dörfler 			}
405a409d733SAxel Dörfler 		}
406a409d733SAxel Dörfler 
407a409d733SAxel Dörfler 		x += bufferList.return_playback_buffer_size;
408a409d733SAxel Dörfler 		exchanged++;
409a409d733SAxel Dörfler 	}
410a409d733SAxel Dörfler 
411*425ac1b6SAlexander von Gluck IV 	printf("%ld buffers exchanged while playing (%lu frames played (%lld)).\n",
412a409d733SAxel Dörfler 		exchanged, x, bufferInfo.played_frames_count);
41302b34466SAxel Dörfler 
41402b34466SAxel Dörfler 	// clear buffers
41502b34466SAxel Dörfler 
41602b34466SAxel Dörfler 	for (int32 i = 0; i < bufferList.return_playback_buffers; i++) {
41702b34466SAxel Dörfler 		size_t stride = bufferList.playback_buffers[i][0].stride;
41802b34466SAxel Dörfler 		for (int32 channel = 0; channel < sDescription.output_channel_count;
41902b34466SAxel Dörfler 				channel++) {
42002b34466SAxel Dörfler 			char* dest = bufferList.playback_buffers[i][channel].base;
42102b34466SAxel Dörfler 			for (uint32 frame = bufferList.return_playback_buffer_size;
42202b34466SAxel Dörfler 					frame-- > 0; ) {
42302b34466SAxel Dörfler 				set_frame(dest, formatInfo.output.format, 0);
42402b34466SAxel Dörfler 				dest += stride;
42502b34466SAxel Dörfler 			}
42602b34466SAxel Dörfler 		}
42702b34466SAxel Dörfler 	}
42802b34466SAxel Dörfler 
42902b34466SAxel Dörfler 	if (ioctl(sDevice, B_MULTI_BUFFER_FORCE_STOP, NULL, 0) < B_OK) {
43002b34466SAxel Dörfler 		printf("Stopping audio failed: %s\n", strerror(errno));
43102b34466SAxel Dörfler 	}
43202b34466SAxel Dörfler }
43302b34466SAxel Dörfler 
43402b34466SAxel Dörfler 
43502b34466SAxel Dörfler static cmd_entry sBuiltinCommands[] = {
43602b34466SAxel Dörfler 	{"rate", do_rate, "Set sample rate"},
43702b34466SAxel Dörfler 	{"format", do_format, "Set sample format"},
43802b34466SAxel Dörfler 	{"desc", do_desc, "Shows description"},
43902b34466SAxel Dörfler 	{"channels", do_channels, "Shows enabled/disabled channels"},
44002b34466SAxel Dörfler 	{"play", do_play, "Plays a tone"},
44102b34466SAxel Dörfler 	{"help", do_help, "prints this help text"},
44202b34466SAxel Dörfler 	{"quit", NULL, "exits the application"},
44302b34466SAxel Dörfler 	{NULL, NULL, NULL},
44402b34466SAxel Dörfler };
44502b34466SAxel Dörfler 
44602b34466SAxel Dörfler 
44702b34466SAxel Dörfler static void
do_help(int argc,char ** argv)44802b34466SAxel Dörfler do_help(int argc, char** argv)
44902b34466SAxel Dörfler {
45002b34466SAxel Dörfler 	printf("Available commands:\n");
45102b34466SAxel Dörfler 
45202b34466SAxel Dörfler 	for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) {
45302b34466SAxel Dörfler 		printf("%8s - %s\n", command->name, command->help);
45402b34466SAxel Dörfler 	}
45502b34466SAxel Dörfler }
45602b34466SAxel Dörfler 
45702b34466SAxel Dörfler 
45802b34466SAxel Dörfler //	#pragma mark -
45902b34466SAxel Dörfler 
46002b34466SAxel Dörfler 
46102b34466SAxel Dörfler int
main(int argc,char ** argv)46202b34466SAxel Dörfler main(int argc, char** argv)
46302b34466SAxel Dörfler {
46402b34466SAxel Dörfler 	if (argc != 2) {
46502b34466SAxel Dörfler 		fprintf(stderr, "Usage: %s <device>\n", __progname);
46602b34466SAxel Dörfler 		return 1;
46702b34466SAxel Dörfler 	}
46802b34466SAxel Dörfler 
46902b34466SAxel Dörfler 	// open driver
47002b34466SAxel Dörfler 
47102b34466SAxel Dörfler 	sDevice = open(argv[1], O_RDWR);
47202b34466SAxel Dörfler 	if (sDevice < 0) {
47302b34466SAxel Dörfler 		fprintf(stderr, "%s: Could not open \"%s\": %s\n", __progname, argv[1],
47402b34466SAxel Dörfler 			strerror(errno));
47502b34466SAxel Dörfler 		return 1;
47602b34466SAxel Dörfler 	}
47702b34466SAxel Dörfler 
47802b34466SAxel Dörfler 	// get description
47902b34466SAxel Dörfler 
48002b34466SAxel Dörfler 	memset(&sDescription, 0, sizeof(multi_description));
48102b34466SAxel Dörfler 	sDescription.info_size = sizeof(multi_description);
48202b34466SAxel Dörfler 	sDescription.request_channel_count = MAX_CHANNELS;
48302b34466SAxel Dörfler 	sDescription.channels = sChannelInfo;
48402b34466SAxel Dörfler 
48502b34466SAxel Dörfler 	if (ioctl(sDevice, B_MULTI_GET_DESCRIPTION, &sDescription,
48602b34466SAxel Dörfler 			sizeof(multi_description)) < 0) {
48702b34466SAxel Dörfler 		fprintf(stderr, "%s: Getting description failed: %s\n", __progname,
48802b34466SAxel Dörfler 			strerror(errno));
48902b34466SAxel Dörfler 		close(sDevice);
49002b34466SAxel Dörfler 		return 1;
49102b34466SAxel Dörfler 	}
49202b34466SAxel Dörfler 
49302b34466SAxel Dörfler 	// get enabled channels
49402b34466SAxel Dörfler 
49502b34466SAxel Dörfler 	multi_channel_enable channelEnable;
49602b34466SAxel Dörfler 	uint32 enabled;
49702b34466SAxel Dörfler 
49802b34466SAxel Dörfler 	channelEnable.info_size = sizeof(multi_channel_enable);
49902b34466SAxel Dörfler 	channelEnable.enable_bits = (uchar*)&enabled;
50002b34466SAxel Dörfler 
50102b34466SAxel Dörfler 	if (ioctl(sDevice, B_MULTI_GET_ENABLED_CHANNELS, &channelEnable,
50202b34466SAxel Dörfler 			sizeof(channelEnable)) < B_OK) {
50302b34466SAxel Dörfler 		fprintf(stderr, "Failed on B_MULTI_GET_ENABLED_CHANNELS: %s\n",
50402b34466SAxel Dörfler 			strerror(errno));
50502b34466SAxel Dörfler 		return 1;
50602b34466SAxel Dörfler 	}
50702b34466SAxel Dörfler 
50802b34466SAxel Dörfler 	sEnabledChannels = enabled;
50902b34466SAxel Dörfler 
51002b34466SAxel Dörfler 	while (true) {
51102b34466SAxel Dörfler 		printf("> ");
51202b34466SAxel Dörfler 		fflush(stdout);
51302b34466SAxel Dörfler 
51402b34466SAxel Dörfler 		char line[1024];
51502b34466SAxel Dörfler 		if (fgets(line, sizeof(line), stdin) == NULL)
51602b34466SAxel Dörfler 			break;
51702b34466SAxel Dörfler 
51802b34466SAxel Dörfler         argc = 0;
51902b34466SAxel Dörfler         argv = build_argv(line, &argc);
52002b34466SAxel Dörfler         if (argv == NULL || argc == 0)
52102b34466SAxel Dörfler             continue;
52202b34466SAxel Dörfler 
52302b34466SAxel Dörfler         int length = strlen(argv[0]);
52402b34466SAxel Dörfler 
52502b34466SAxel Dörfler 		if (!strcmp(argv[0], "quit")
52602b34466SAxel Dörfler 			|| !strcmp(argv[0], "exit")
52702b34466SAxel Dörfler 			|| !strcmp(argv[0], "q"))
52802b34466SAxel Dörfler 			break;
52902b34466SAxel Dörfler 
53002b34466SAxel Dörfler 		bool found = false;
53102b34466SAxel Dörfler 
53202b34466SAxel Dörfler 		for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) {
53302b34466SAxel Dörfler 			if (!strncmp(command->name, argv[0], length)) {
53402b34466SAxel Dörfler 				command->func(argc, argv);
53502b34466SAxel Dörfler 				found = true;
53602b34466SAxel Dörfler 				break;
53702b34466SAxel Dörfler 			}
53802b34466SAxel Dörfler 		}
53902b34466SAxel Dörfler 
54002b34466SAxel Dörfler 		if (!found)
54102b34466SAxel Dörfler 			fprintf(stderr, "Unknown command \"%s\". Type \"help\" for a list of commands.\n", argv[0]);
54202b34466SAxel Dörfler 
54302b34466SAxel Dörfler 		free(argv);
54402b34466SAxel Dörfler 	}
54502b34466SAxel Dörfler 
54602b34466SAxel Dörfler 	close(sDevice);
54702b34466SAxel Dörfler 	return 0;
54802b34466SAxel Dörfler }
54902b34466SAxel Dörfler 
550