1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
testnull11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20     bsd20_a.c
21 	Written by Yamate Keiichiro <keiich-y@is.aist-nara.ac.jp>
22 */
23 
24 /*
25  *  BSD/OS 2.0 audio
26  */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif /* HAVE_CONFIG_H */
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <i386/isa/sblast.h>
34 
35 #include "timidity.h"
36 #include "output.h"
37 #include "controls.h"
38 #include "timer.h"
39 #include "instrum.h"
40 #include "playmidi.h"
41 #include "miditrace.h"
42 
43 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
44 static void close_output(void);
45 static int output_data(char *buf, int32 nbytes);
46 static int acntl(int request, void *arg);
47 
48 /* export the playback mode */
49 
50 #define dpm bsdi_play_mode
51 
52 PlayMode dpm = {
53     DEFAULT_RATE, PE_SIGNED|PE_MONO, PF_PCM_STREAM|PF_CAN_TRACE,
54     -1,
55     {0}, /* default: get all the buffer fragments you can */
56     "BSD/OS sblast dsp", 'd',
57     "/dev/sb_dsp",
58     open_output,
59     close_output,
60     output_data,
61     acntl
62 };
63 
64 static int open_output(void)
65 {
66     int fd, tmp, warnings=0;
67 
68     if ((fd=open(dpm.name, O_RDWR | O_NDELAY, 0)) < 0)
69     {
70 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
71 		  dpm.name, strerror(errno));
72 	return -1;
73     }
74 
75     /* They can't mean these */
76     dpm.encoding &= ~(PE_ULAW|PE_ALAW|PE_BYTESWAP);
77 
78 
79     /* Set sample width to whichever the user wants. If it fails, try
80        the other one. */
81 
82     if (dpm.encoding & PE_16BIT)
83     {
84 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: sblast only 8bit",
85 		  dpm.name);
86 	close(fd);
87 	return -1;
88     }
89 
90     tmp = ((~dpm.encoding) & PE_16BIT) ? PCM_8 : 0;
91     ioctl(fd, DSP_IOCTL_COMPRESS, &tmp);
92     dpm.encoding &= ~PE_SIGNED;
93 
94     /* Try stereo or mono, whichever the user wants. If it fails, try
95        the other. */
96 
97     tmp=(dpm.encoding & PE_MONO) ? 0 : 1;
98     ioctl(fd, DSP_IOCTL_STEREO, &tmp);
99 
100   /* Set the sample rate */
101 
102     tmp=dpm.rate * ((dpm.encoding & PE_MONO) ? 1 : 2);
103     ioctl(fd, DSP_IOCTL_SPEED, &tmp);
104     if (tmp != dpm.rate)
105     {
106 	dpm.rate=tmp / ((dpm.encoding & PE_MONO) ? 1 : 2);;
107 	ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
108 		  "Output rate adjusted to %d Hz", dpm.rate);
109 	warnings=1;
110     }
111 
112     /* Older VoxWare drivers don't have buffer fragment capabilities */
113 
114     if (dpm.extra_param[0])
115     {
116 	ctl->cmsg(CMSG_WARNING, VERB_NORMAL,
117 		  "%s doesn't support buffer fragments", dpm.name);
118 	warnings=1;
119     }
120 
121     tmp = 16384;
122     ioctl(fd, DSP_IOCTL_BUFSIZE, &tmp);
123 
124     dpm.fd = fd;
125     return warnings;
126 }
127 
128 static int output_data(char *buf, int32 nbytes)
129 {
130     while ((-1==write(dpm.fd, buf, nbytes)) && errno==EINTR)
131 	;
132 }
133 
134 static void close_output(void)
135 {
136     if(dpm.fd != -1)
137     {
138 	close(dpm.fd);
139 	dpm.fd = -1;
140     }
141 }
142 
143 static int acntl(int request, void *arg)
144 {
145     switch(request)
146     {
147       case PM_REQ_DISCARD:
148 	return ioctl(dpm.fd, DSP_IOCTL_RESET);
149 
150       case PM_REQ_PLAY_START: /* Called just before playing */
151       case PM_REQ_PLAY_END: /* Called just after playing */
152         return 0;
153     }
154     return -1;
155 }
156