⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 server_c.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    TiMidity++ -- MIDI to WAVE converter and player    Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>    Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA    server_c.c - TiMidity server written by Masanao Izumo <iz@onicos.co.jp>        Mon Apr 5 1999: Initial created.    Launch TiMidity server: (example)    % timidity -ir 7777    Protcol note:    The protocol is based on OSS interface.    TiMidity server has 2 TCP/IP connection.  They are control port and    data port.    Control port:        ASCII text protocol like FTP control port. See command_help for        control protocol in this source code.    Data port:        One way Binary stream data from client to server. The format of        stream is same as OSS sequencer stream.    TODO:        Protocol specification to be documented.*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include <signal.h>#ifdef HAVE_SYS_SOUNDCARD_H#include <sys/soundcard.h>#else#include "server_defs.h"#endif /* HAVE_SYS_SOUNDCARD_H */#include "timidity.h"#include "common.h"#include "controls.h"#include "instrum.h"#include "playmidi.h"#include "readmidi.h"#include "recache.h"#include "output.h"#include "aq.h"#include "timer.h"/* #define DEBUG_DUMP_SEQ 1 */#define MIDI_COMMAND_PER_SEC	100#define DEFAULT_LOW_TIMEAT	0.4#define DEFAULT_HIGH_TIMEAT	0.6#define DONT_STOP_AUDIO	1#define DEFAULT_TIMEBASE	100 /* HZ? */#define MAXTICKDIFF		150#define SIG_TIMEOUT_SEC		3static int cmd_help(int argc, char **argv);static int cmd_open(int argc, char **argv);static int cmd_close(int argc, char **argv);static int cmd_timebase(int argc, char **argv);static int cmd_reset(int argc, char **argv);static int cmd_patch(int argc, char **argv);static int cmd_quit(int argc, char **argv);static int cmd_queue(int argc, char **argv);static int cmd_maxqueue(int argc, char **argv);static int cmd_time(int argc, char **argv);static int cmd_nop(int argc, char **argv);static int cmd_autoreduce(int argc, char **argv);static int cmd_setbuf(int argc, char **argv);struct{    char *cmd, *help;    int minarg, maxarg;    int (* proc)(int argc, char **argv);  /* argv[0] is command name					   * argv[1..argc-1] is the arg.					   * return: 0=success, -1=fatal-error,					   *         1=connection-closed					   */} cmd_table[] ={    {"HELP",	"HELP\tDisplay this message",	1, 1, cmd_help},    {"OPEN",	"OPEN {lsb|msb}\n"	"\tOpen data connection\n"	"\tlsb: The byte order of data stream is LSB\n"	"\tmsb: The byte order of data stream is MSB",	2, 2, cmd_open},    {"CLOSE",	"CLOSE\tShutdown current data connection",	1, 1, cmd_close},    {"TIMEBASE",	"TIMEBASE [timebase]\n\tSet time base",	1, 2, cmd_timebase},    {"RESET",	"RESET\tInitialize all of MIDI status",	1, 1, cmd_reset},    {"PATCH",	"PATCH {drumset|bank} <bank-no> <prog-no>\n\tLoad specified patch",	4, 4, cmd_patch},    {"QUIT",	"QUIT\tClose control connection",	1, 1, cmd_quit},    {"QUEUE",	"QUEUE\tTiMidity tells the time of audio buffer queue in second",	1, 1, cmd_queue},    {"MAXQUEUE",	"MAXQUEUE\n"	"\tTiMidity tells the maxmum time of audio buffer queue in second",	1, 1, cmd_maxqueue},    {"TIME",	"TIME\tTiMidity tells the current playing time in second",	1, 1, cmd_time},    {"NOP",	"NOP\tDo nothing",	1, 1, cmd_nop},    {"AUTOREDUCE",	"AUTOREDUCE {on|off} [msec]\n\tEnable/Disable auto voice reduction",	2, 3, cmd_autoreduce},    {"SETBUF",	"SETBUF low hi\n\tSpecify low/hi sec of buffer queue",	3, 3, cmd_setbuf},    {NULL, NULL, 0, 0, NULL} /* terminate */};/*TEMPO [<tempo>]\n\	Change the tempo.  If the argument is omitted, TiMidity tells the\n\	current tempo.\n\KEYSHIFT <{+|-}offs>\n\	Change the base key. (0 to reset)\n\SPEED <{+|-}offs>\n\	Change the play speed. (0 to reset)\n\MODE {gs|xg|gm}\n\	Specify default MIDI system mode\n\SYNTH [gus|awe]\n\	Specify Synth type emulation. (no argument to default)\n\*/static int ctl_open(int using_stdin, int using_stdout);static void ctl_close(void);static int ctl_read(int32 *valp);static int cmsg(int type, int verbosity_level, char *fmt, ...);static void ctl_event(CtlEvent *e);static void ctl_pass_playing_list(int n, char *args[]);/**********************************//* export the interface functions */#define ctl server_control_modeControlMode ctl={    "remote interface", 'r',    1,0,0,    0,    ctl_open,    ctl_close,    ctl_pass_playing_list,    ctl_read,    cmsg,    ctl_event};struct fd_read_buffer{    char buff[BUFSIZ];    /* count: beginning of read pointer     * size:  end of read pointer     * fd:    file descripter for input     */    int count, size, fd;};static int fdgets(char *buff, size_t buff_size, struct fd_read_buffer *p);static int fdputs(char *s, int fd);static uint32 data2long(uint8* data);static uint16 data2short(uint8* data);static int do_control_command_nonblock(void);static struct fd_read_buffer control_fd_buffer;static int data_fd = -1, control_fd = -1;static int data_port, control_port;static int is_lsb_data = 1;static int curr_timebase = DEFAULT_TIMEBASE;static int32 sample_correction;static int32 sample_increment;static int32 sample_correction;static int32 sample_cum;static int32 curr_event_samples, event_time_offset;static int32 curr_tick, tick_offs;static double start_time;static int tmr_running;static int is_system_prefix = 0;static struct sockaddr_in control_client;static double low_time_at = 0.3;static double high_time_at = 0.5;static FILE *outfp;/*ARGSUSED*/static int ctl_open(int using_stdin, int using_stdout){    ctl.opened = 1;    ctl.flags &= ~(CTLF_LIST_RANDOM|CTLF_LIST_SORT);    if(using_stdout)	outfp = stderr;    else	outfp = stdout;    return 0;}static void ctl_close(void){    if(!ctl.opened)	return;    if(data_fd != -1)    {	close(data_fd);	data_fd = -1;    }    if(control_fd != -1)    {	close(control_fd);	control_fd = -1;    }}/*ARGSUSED*/static int ctl_read(int32 *valp){    if(data_fd != -1)	do_control_command_nonblock();    return RC_NONE;}static int cmsg(int type, int verbosity_level, char *fmt, ...){    va_list ap;    if((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&       ctl.verbosity < verbosity_level)	return 0;    if(outfp == NULL)	outfp = stderr;    va_start(ap, fmt);    vfprintf(outfp, fmt, ap);    fputs(NLS, outfp);    fflush(outfp);    va_end(ap);    return 0;}static void ctl_event(CtlEvent *e){}static int pasv_open(int *port){    int sfd;    struct sockaddr_in server;    if((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)    {	perror("socket");	return -1;    }    memset(&server, 0, sizeof(server));    server.sin_port        = htons(*port);    server.sin_family      = AF_INET;    server.sin_addr.s_addr = htonl(INADDR_ANY);#ifdef SO_REUSEADDR    {	int on = 1;	setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (caddr_t)&on, sizeof(on));    }#endif /* SO_REUSEADDR */    ctl.cmsg(CMSG_INFO, VERB_DEBUG, "Bind TCP/IP port=%d", *port);    if(bind(sfd, (struct sockaddr *)&server, sizeof(server)) < 0)    {	perror("bind");	close(sfd);	return -1;    }    if(*port == 0)    {	int len = sizeof(server);	if(getsockname(sfd, (struct sockaddr *)&server, &len) < 0)	{	    perror("getsockname");	    close(sfd);	    return -1;	}	*port = ntohs(server.sin_port);    }    /* Set it up to wait for connections. */    if(listen(sfd, 1) < 0)    {	perror("listen");	close(sfd);	return -1;    }    return sfd;}static RETSIGTYPE sig_timeout(int sig){    signal(SIGALRM, sig_timeout); /* For SysV base */    /* Expect EINTR */}static void doit(void);static int send_status(int status, char *message, ...);static void compute_sample_increment(void);static void server_reset(void);static void ctl_pass_playing_list(int n, char *args[]){    int sock;    if(n != 2 && n != 1)    {	fprintf(stderr, "Usage: timidity -ir control-port [data-port]\n");	return;    }#ifdef SIGPIPE    signal(SIGPIPE, SIG_IGN);    /* Handle broken pipe */#endif /* SIGPIPE */    control_port = atoi(args[0]);    if(n == 2)	data_port = atoi(args[1]);    else	data_port = 0;    if (control_port) {	sock = pasv_open(&control_port);	if(sock == -1)	    return;    }    opt_realtime_playing = 1; /* Enable loading patch while playing */    allocate_cache_size = 0; /* Don't use pre-calclated samples *//*  aq_set_soft_queue(-1.0, 0.0); */    alarm(0);    signal(SIGALRM, sig_timeout);    play_mode->close_output();    while(1)    {	int addrlen;	addrlen = sizeof(control_client);	memset(&control_client, 0, addrlen);	if (control_port) {	    if((control_fd = accept(sock,				(struct sockaddr *)&control_client,				&addrlen)) < 0)	    {		if(errno == EINTR)		    continue;		perror("accept");		close(sock);		return;	    }	}	else control_fd = 0;	if(play_mode->open_output() < 0)	{	    ctl.cmsg(CMSG_FATAL, VERB_NORMAL,		     "Couldn't open %s (`%c')",		     play_mode->id_name, play_mode->id_character);	    send_status(510, "Couldn't open %s (`%c')",			play_mode->id_name, play_mode->id_character);	    if (control_port) {		close(control_fd);		control_fd = 1;	    }	    continue;	}	server_reset();	ctl.cmsg(CMSG_INFO, VERB_NOISY, "Connected");	doit();	ctl.cmsg(CMSG_INFO, VERB_NOISY, "Connection closed");	play_mode->close_output();	if(control_fd != -1 && control_port)	{	    close(control_fd);	    control_fd = -1;	}	if(data_fd != -1)	{	    close(data_fd);	    data_fd = -1;	}	free_instruments(0);	free_global_mblock();	if (!control_port)	    break;    }}#define MAX_GETCMD_PARAMS 8/* return: * 0: success * 1: error *-1: fatal error (will be close the connection) */static int control_getcmd(char **params, int *nparams){    static char buff[BUFSIZ];    int n;    /* read line */    n = fdgets(buff, sizeof(buff), &control_fd_buffer);    if(n == -1)    {	perror("read");	return -1;    }    if(n == 0)	return 1;    if((params[0] = strtok(buff, " \t\r\n\240")) == NULL)	return 0;    *nparams = 0;    while(params[*nparams] && *nparams < MAX_GETCMD_PARAMS)	params[++(*nparams)] = strtok(NULL," \t\r\n\240");    return 0;}static int send_status(int status, char *message, ...){    va_list ap;    char buff[BUFSIZ];    va_start(ap, message);    sprintf(buff, "%03d ", status);    vsnprintf(buff + 4, sizeof(buff) - 5, message, ap);    va_end(ap);    strncat(buff, "\n", BUFSIZ - strlen(buff) - 1);    buff[BUFSIZ-1] = '\0';      /* force terminate */    if(write(control_fd, buff, strlen(buff)) == -1)	return -1;    return 0;}static void seq_play_event(MidiEvent *ev){    if(tmr_running)	ev->time = curr_event_samples;    else    {	if(IS_STREAM_TRACE)	{	    event_time_offset += play_mode->rate / MIDI_COMMAND_PER_SEC;	    ev->time = curr_event_samples;	}	else	{	    double past_time = get_current_calender_time() - start_time;	    if(play_mode->flag & PF_PCM_STREAM)		past_time += high_time_at;	    ev->time = (int32)(past_time * play_mode->rate);	}    }    ev->time += event_time_offset;    play_event(ev);}static void tmr_reset(void){    curr_event_samples =	event_time_offset =	    sample_cum = 0;    playmidi_tmr_reset();    curr_timebase = DEFAULT_TIMEBASE;    curr_tick = tick_offs = 0;    start_time = get_current_calender_time();}static void compute_sample_increment(void){    double a;    a = (double)current_play_tempo * (double)play_mode->rate	* (65536.0/500000.0) / (double)curr_timebase,    sample_correction = (int32)(a) & 0xFFFF;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -