1/*
2 * Driver for the NeXT / Apple soundkit objects for use on OpenStep
3 * systems. Based on the older sound drivers, converted into the new
4 * style framework by taking a long hard look at esound.c.
5 *
6 * -bat. 06/09/2000
7 */
8
9#import <stdio.h>
10#import <stdlib.h>
11#import <unistd.h>
12#import <SoundKit/SoundKit.h>
13
14#import "sysdep/sysdep_dsp.h"
15#import "sysdep/sysdep_dsp_priv.h"
16#import "sysdep/plugin_manager.h"
17
18/*
19 * Destroy function - we release the playStream and free up
20 * the dsp structure.
21 */
22
23static void
24soundkit_dsp_destroy(struct sysdep_dsp_struct *dsp)
25{
26	NXPlayStream *playStream = (NXPlayStream*)dsp->_priv;
27
28	[playStream release];
29
30	free(dsp);
31}
32
33/*
34 * Write a block of data to the sound object. We take pains to make sure it
35 * in the correct format by copying it around the place quite a lot - this
36 * makes 8 bit sound rather slow as we cannot write it to the device
37 * directly due to an intel bug.
38 */
39
40static int
41soundkit_dsp_write(struct sysdep_dsp_struct *dsp,
42		unsigned char *data, int count)
43{
44	static int theTag = 1;
45	static long buff_size = 0;
46	static unsigned char *out_buff = NULL;
47
48	BOOL isStereo = (dsp->hw_info.type & SYSDEP_DSP_STEREO) ? YES : NO;
49	NXPlayStream *playStream = (NXPlayStream*)dsp->_priv;
50	long bytes = sizeof(short) * count * (isStereo ? 2 : 1);
51
52	/* do a malloc if necessary */
53	if(bytes > buff_size) {
54		if(out_buff)
55			free(out_buff);
56		out_buff = malloc(bytes);
57		if(!out_buff)
58			return 0;
59		buff_size = bytes;
60	}
61
62	/* do the byte swap and write the block */
63	SNDSwapHostToSound(out_buff, data, count,
64			isStereo ? 2: 1, SND_FORMAT_LINEAR_16);
65	[playStream playBuffer:out_buff size:bytes tag:theTag++];
66
67	return count;
68}
69
70/*
71 * Creation function.
72 */
73
74static void*
75soundkit_dsp_create(const void *flags)
76{
77	NXPlayStream *playStream = nil;
78	NXSoundOut *soundOut = nil;
79	NXSoundParameters *soundParams = nil;
80	SNDSoundStruct *soundStruct = NULL;
81	char *soundHost = getenv("SOUNDHOST");
82	id priv = nil;
83	struct sysdep_dsp_struct *dsp = NULL;
84	const struct sysdep_dsp_create_params *params = flags;
85
86	/* allocate the dsp struct */
87	if (!(dsp = calloc(1, sizeof(struct sysdep_dsp_struct))))
88	{
89		perror("error malloc failed for struct sysdep_dsp_struct\n");
90		return NULL;
91	}
92
93	/* create sound object (possibly remotely) */
94	if(soundHost) {
95		soundOut = [[NXSoundOut alloc]
96			initOnHost:[NSString stringWithCString:soundHost]];
97		if(!soundOut) {
98			fprintf(stderr,
99				"could not initialise sound object on %s\n",
100				soundHost);
101	      		return NULL;
102	    	} else
103			fprintf(stderr, "info: soundkit: send sound to %s\n",
104					soundHost);
105	} else
106		soundOut = [NXSoundOut new];
107
108	if(!soundOut) {
109		fprintf(stderr,"could not initialise sound object\n");
110		return NULL;
111	}
112
113	/* create a parameters object - always 16 bit please ! */
114	dsp->hw_info.type |= SYSDEP_DSP_16BIT;
115	if(params->type & SYSDEP_DSP_STEREO) {
116		SNDAlloc(&soundStruct, 0, SND_FORMAT_LINEAR_16,
117				params->samplerate, 2, 0);
118		dsp->hw_info.type |= SYSDEP_DSP_STEREO;
119	} else {
120		SNDAlloc(&soundStruct, 0, SND_FORMAT_LINEAR_16,
121				params->samplerate, 1, 0);
122	}
123	soundParams = [[NXSoundParameters alloc]
124			initFromSoundStruct:soundStruct];
125	if(!soundParams) {
126		fprintf(stderr,"could not create sound parameters\n");
127		return NULL;
128	}
129
130	/* print the info */
131	fprintf(stderr, "info: soundkit: %s sound at %d hz\n",
132			(dsp->hw_info.type & SYSDEP_DSP_STEREO) ?
133			"stereo" : "mono", params->samplerate);
134
135	/* create the stream object */
136	playStream = [[NXPlayStream alloc]
137		initOnDevice:soundOut withParameters:soundParams];
138	if(!playStream) {
139		fprintf(stderr,"could not create play stream\n");
140		return NULL;
141	}
142
143	/* fill in the functions and some data */
144	dsp->_priv = playStream;
145	dsp->write = soundkit_dsp_write;
146	dsp->destroy = soundkit_dsp_destroy;
147	dsp->hw_info.type = params->type;
148	dsp->hw_info.samplerate = params->samplerate;
149
150	/* activate and return */
151
152	[playStream activate];
153	return dsp;
154}
155
156/*
157 * The public variables structure
158 */
159
160const struct plugin_struct sysdep_dsp_soundkit = {
161	"soundkit",
162	"sysdep_dsp",
163	"NeXT SoundKit plugin",
164	NULL, 				/* no options */
165	NULL,				/* no init */
166	NULL,				/* no exit */
167	soundkit_dsp_create,
168	3				/* high priority */
169};
170