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
11 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 npipe_.c
21
22 Functions to output raw sound data to a windows Named Pipe.
23
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #include <stdio.h>
30
31 #ifdef __POCC__
32 #include <sys/types.h>
33 #endif //for off_t
34
35 #ifdef __W32__
36 #include <windows.h>
37 #include <stdlib.h>
38 #include <io.h>
39 #endif
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif /* HAVE_UNISTD_H */
44
45 #ifdef STDC_HEADERS
46 #include <stdlib.h>
47 #include <string.h>
48 #include <ctype.h>
49 #elif HAVE_STRINGS_H
50 #include <strings.h>
51 #endif
52
53 #include <fcntl.h>
54
55 #ifdef __FreeBSD__
56 #include <stdio.h>
57 #endif
58
59 #include "timidity.h"
60 #include "common.h"
61 #include "output.h"
62 #include "controls.h"
63 #include "instrum.h"
64 #include "playmidi.h"
65 #include "readmidi.h"
66
67 //#define PIPE_BUFFER_SIZE (AUDIO_BUFFER_SIZE * 8)
68 #define PIPE_BUFFER_SIZE (88200)
69 static HANDLE hPipe=NULL;
70 OVERLAPPED pipe_ovlpd;
71 HANDLE hPipeEvent;
72 static volatile int pipe_close=-1;
73 static volatile int clear_pipe=-1;
74
75 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
76 static void close_output(void);
77 static int output_data(char *buf, int32 bytes);
78 static int acntl(int request, void *arg);
79
80 /* export the playback mode */
81
82 #define dpm npipe_play_mode
83
84 PlayMode dpm = {
85 DEFAULT_RATE,
86 PE_16BIT|PE_SIGNED, PF_PCM_STREAM|PF_CAN_TRACE,
87 -1,
88 {0,0,0,0,0},
89 "Windows Named Pipe", 'N',
90 NULL,
91 open_output,
92 close_output,
93 output_data,
94 acntl
95 };
96
97 /*************************************************************************/
98
npipe_output_open(const char * pipe_name)99 static int npipe_output_open(const char *pipe_name)
100 {
101 char PipeName[256];
102 DWORD ret;
103 DWORD n;
104 int i;
105
106
107 if (hPipe != NULL) return 0;
108 hPipeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
109 memset( &pipe_ovlpd, 0, sizeof(OVERLAPPED));
110 pipe_ovlpd.hEvent = hPipeEvent;
111
112 sprintf(PipeName, "\\\\.\\pipe\\%s", pipe_name);
113 hPipe = CreateNamedPipe(PipeName, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
114 // PIPE_WAIT|
115 PIPE_READMODE_BYTE |PIPE_TYPE_BYTE, 2,
116 PIPE_BUFFER_SIZE, 0, 0, NULL);
117 if (hPipe == INVALID_HANDLE_VALUE) {
118 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't create Named Pipe %s : %ld",
119 pipe_name, GetLastError());
120 return -1;
121 }
122 ret = ConnectNamedPipe(hPipe, &pipe_ovlpd);
123 if ( (ret == 0) && (ERROR_IO_PENDING!=GetLastError()) ){
124 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "CnnectNamePipe(%ld) error %s",
125 GetLastError(), pipe_name);
126 CloseHandle(hPipe);
127 hPipe=NULL;
128 return -1;
129 }
130 // WaitForSingleObject(pipe_ovlpd.hPipeEvent, 1000);
131
132 return 0;
133 }
134
open_output(void)135 static int open_output(void)
136 {
137 dpm.encoding = validate_encoding(dpm.encoding, 0, 0);
138
139 if(dpm.name == NULL) {
140 if (NULL==current_file_info || NULL==current_file_info->filename){
141 return -1;
142 }
143 }else{
144 if ( -1 == npipe_output_open(dpm.name))
145 return -1;
146 }
147 dpm.fd = 1;
148 // clear_pipe = 0;
149 return 0;
150 }
151
output_data(char * buf,int32 bytes)152 static int output_data(char *buf, int32 bytes)
153 {
154 DWORD n;
155 int ret;
156 int32 retnum;
157 retnum = bytes;
158 DWORD length;
159 char *clear_data;
160
161 if (hPipe == NULL) return -1;
162 if ( ( 0 == PeekNamedPipe(hPipe,NULL,0,NULL,&length,NULL)) &&
163 (GetLastError()==ERROR_BAD_PIPE) ) return -1;
164 if(dpm.fd == -1) return -1;
165 if (pipe_close = 0){
166 hPipe=NULL;
167 dpm.fd = -1;
168 return retnum;
169 }
170
171 if (0 != PeekNamedPipe(hPipe,NULL,0,NULL,&length,NULL)){
172 if(clear_pipe == -1){
173 if(bytes <= PIPE_BUFFER_SIZE-length){
174 ret=WriteFile(hPipe,buf,bytes,&n,&pipe_ovlpd);
175 if( (GetLastError() != ERROR_SUCCESS) &&
176 (GetLastError() != ERROR_IO_PENDING) &&
177 (GetLastError() != ERROR_BAD_PIPE) ){ //why BAD_PIPE occurs here?
178 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "npipe_a_error %s: %ld",
179 dpm.name, GetLastError());
180 if(hPipe != NULL) CloseHandle(hPipe);
181 hPipe=NULL;
182 dpm.fd = -1;
183 return -1;
184 }
185 }else{
186 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "npipe_a_errror overflow");
187 }
188 }else{
189 if(length < audio_buffer_size){
190 clear_data = (char*)safe_malloc(audio_buffer_size-length);
191 memset(clear_data, 0, audio_buffer_size-length);
192 WriteFile(hPipe,clear_data,audio_buffer_size-length,&n,&pipe_ovlpd);
193 free(clear_data);
194 if( (GetLastError() != ERROR_SUCCESS) &&
195 (GetLastError() != ERROR_IO_PENDING) &&
196 (GetLastError() != ERROR_BAD_PIPE) ){ //why BAD_PIPE occurs here?
197 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "npipe_a_error %s: %ld",
198 dpm.name, GetLastError());
199 if(hPipe != NULL) CloseHandle(hPipe);
200 hPipe=NULL;
201 dpm.fd = -1;
202 return -1;
203 }
204 clear_pipe =-1;
205 }
206 }
207 }
208 return retnum;
209 }
210
close_output(void)211 static void close_output(void)
212 {
213 if(dpm.fd != -1){
214 CloseHandle(hPipeEvent);
215 CloseHandle(hPipe);
216 hPipe=NULL;
217 dpm.fd = -1;
218 }
219 }
220
acntl(int request,void * arg)221 static int acntl(int request, void *arg)
222 {
223 switch(request) {
224 case PM_REQ_PLAY_START:
225 return 0;
226 case PM_REQ_PLAY_END:
227 return 0;
228 case PM_REQ_DISCARD:
229 case PM_REQ_FLUSH:
230 // clear_pipe=0;
231 return 0;
232
233 }
234 return -1;
235 }
236
npipe_a_pipe_close()237 int npipe_a_pipe_close()
238 {
239 int count;
240 if (hPipe == NULL) return;
241 pipe_close=0;
242 count = 100;
243 while( (hPipe != NULL) && (count >0)) Sleep(10);
244 if (hPipe != NULL){
245 CloseHandle(hPipe);
246 hPipe=NULL;
247 }
248
249 }
250
251
252
253