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

📄 tk_c.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    TiMidity++ -- MIDI to WAVE converter and player    Copyright (C) 1999-2002 Masanao Izumo <mo@goice.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*//*================================================================ * * The Tcl/Tk interface for Timidity * written by Takashi Iwai (iwai@dragon.mm.t.u-tokyo.ac.jp) * * Most of the following codes are derived from both motif_ctl.c * and motif_pipe.c.  The communication between Tk program and * timidity is established by a pipe stream as in Motif interface. * On the contrast to motif, the stdin and stdout are assigned * as pipe i/o in Tk interface. * *================================================================*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <stdarg.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include <sys/types.h>#include <sys/ioctl.h>#include <signal.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/sem.h>#include <tcl.h>#include <tk.h>#include <sys/wait.h>#include "timidity.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "readmidi.h"#include "output.h"#include "controls.h"#include "miditrace.h"#include "aq.h"#ifndef TKPROGPATH#define TKPROGPATH PKGLIBDIR "/tkmidity.tcl"#endif /* TKPROGPATH */static void ctl_refresh(void);static void ctl_total_time(int tt);static void ctl_master_volume(int mv);static void ctl_file_name(char *name);static void ctl_current_time(int secs, int v);static void ctl_program(int ch, int val);static void ctl_volume(int channel, int val);static void ctl_expression(int channel, int val);static void ctl_panning(int channel, int val);static void ctl_sustain(int channel, int val);static void ctl_pitch_bend(int channel, int val);static void ctl_lyric(int lyricid);static void ctl_reset(void);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_pass_playing_list(int number_of_files, char *list_of_files[]);static int ctl_blocking_read(int32 *valp);static void ctl_note(int status, int ch, int note, int vel);static void ctl_event(CtlEvent *e);static void k_pipe_printf(char *fmt, ...);static void k_pipe_puts(char *str);static int k_pipe_gets(char *str, int maxlen);static void k_pipe_open(void);static void k_pipe_error(char *st);static int k_pipe_read_ready(void);static int AppInit(Tcl_Interp *interp);static int ExitAll(ClientData clientData, Tcl_Interp *interp,		       int argc, char *argv[]);static int TraceCreate(ClientData clientData, Tcl_Interp *interp,		       int argc, char *argv[]);static int TraceUpdate(ClientData clientData, Tcl_Interp *interp,		    int argc, char *argv[]);static int TraceReset(ClientData clientData, Tcl_Interp *interp,		    int argc, char *argv[]);static void trace_volume(int ch, int val);static void trace_panning(int ch, int val);static void trace_prog_init(int ch);static void trace_prog(int ch, int val);static void trace_bank(int ch, int val);static void trace_sustain(int ch, int val);static void get_child(int sig);static void shm_alloc(void);static void shm_free(int sig);static void start_panel(void);#define MAX_TK_MIDI_CHANNELS	16typedef struct {	int reset_panel;	int multi_part;	int32 last_time, cur_time;	char v_flags[MAX_TK_MIDI_CHANNELS];	int16 cnote[MAX_TK_MIDI_CHANNELS];	int16 cvel[MAX_TK_MIDI_CHANNELS];	int16 ctotal[MAX_TK_MIDI_CHANNELS];	char c_flags[MAX_TK_MIDI_CHANNELS];	Channel channel[MAX_TK_MIDI_CHANNELS];	int wait_reset;} PanelInfo;/**********************************************/#define ctl tk_control_modeControlMode ctl={    "Tcl/Tk interface", 'k',    1,0,0,    0,    ctl_open,    ctl_close,    ctl_pass_playing_list,    ctl_read,    cmsg,    ctl_event};#define FLAG_NOTE_OFF	1#define FLAG_NOTE_ON	2#define FLAG_BANK	1#define FLAG_PROG	2#define FLAG_PAN	4#define FLAG_SUST	8static VOLATILE PanelInfo *Panel;static VOLATILE int child_killed = 0;static int shmid;	/* shared memory id */static int semid;	/* semaphore id */static int pipeAppli[2],pipePanel[2]; /* Pipe for communication with Tcl/Tk process   */static int fpip_in, fpip_out;	/* in and out depends in which process we are */static int child_pid;	               /* Pid for child process *//***********************************************************************//* semaphore utilities                                                 *//***********************************************************************/static void semaphore_P(int sid){    struct sembuf sb;    sb.sem_num = 0;    sb.sem_op  = -1;    sb.sem_flg = 0;    if(semop(sid, &sb, 1) == -1)	perror("semop");}static void semaphore_V(int sid){    struct sembuf sb;    sb.sem_num = 0;    sb.sem_op  = 1;    sb.sem_flg = 0;    if(semop(sid, &sb, 1) == -1)	perror("semop");}/***********************************************************************//* Put controls on the pipe                                            *//***********************************************************************/static int cmsg(int type, int verbosity_level, char *fmt, ...){	char local[2048];#define TOO_LONG	2000	va_list ap;	if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&	    ctl.verbosity<verbosity_level)		return 0;	va_start(ap, fmt);	if (strlen(fmt) > TOO_LONG)		fmt[TOO_LONG] = 0;	if (!ctl.opened) {		vfprintf(stderr, fmt, ap);		fprintf(stderr, "\n");	} else if (type == CMSG_ERROR) {		int32 val;		vsnprintf(local, sizeof(local), fmt, ap);		k_pipe_printf("CERR %d", type);		k_pipe_puts(local);		while (ctl_blocking_read(&val) != RC_NEXT)			;	} else {		vsnprintf(local, sizeof(local), fmt, ap);		k_pipe_printf("CMSG %d", type);		k_pipe_puts(local);	}	va_end(ap);	return 0;}static void ctl_refresh(void){}static void ctl_total_time(int tt){	int centisecs=tt/(play_mode->rate/100);	k_pipe_printf("TIME %d", centisecs);	ctl_current_time(0, 0);}static void ctl_master_volume(int mv){	k_pipe_printf("MVOL %d", mv);}static void ctl_file_name(char *name){	k_pipe_printf("FILE %s", name);}static void ctl_current_time(int secs, int v){    Panel->cur_time = secs;}static void ctl_channel_note(int ch, int note, int vel){	if (vel == 0) {		if (note == Panel->cnote[ch])			Panel->v_flags[ch] = FLAG_NOTE_OFF;		Panel->cvel[ch] = 0;	} else if (vel > Panel->cvel[ch]) {		Panel->cvel[ch] = vel;		Panel->cnote[ch] = note;		Panel->ctotal[ch] = vel * Panel->channel[ch].volume *			Panel->channel[ch].expression / (127*127);		Panel->v_flags[ch] = FLAG_NOTE_ON;	}}static void ctl_note(int status, int ch, int note, int vel){	if (!ctl.trace_playing)		return;	if (ch < 0 || ch >= MAX_TK_MIDI_CHANNELS) return;	if (status != VOICE_ON)		vel = 0;	semaphore_P(semid);	ctl_channel_note(ch, note, vel);	semaphore_V(semid);}static void ctl_program(int ch, int val){        if(ch >= MAX_TK_MIDI_CHANNELS)		return;	if (!ctl.trace_playing)		return;	if (ch < 0 || ch >= MAX_TK_MIDI_CHANNELS) return;	if(channel[ch].special_sample)	    val = channel[ch].special_sample;	else	    val += progbase;	semaphore_P(semid);	Panel->channel[ch].program = val;	Panel->c_flags[ch] |= FLAG_PROG;	semaphore_V(semid);}static void ctl_volume(int ch, int val){        if(ch >= MAX_TK_MIDI_CHANNELS)		return;	if (!ctl.trace_playing)		return;	semaphore_P(semid);	Panel->channel[ch].volume = val;	ctl_channel_note(ch, Panel->cnote[ch], Panel->cvel[ch]);	semaphore_V(semid);}static void ctl_expression(int ch, int val){        if(ch >= MAX_TK_MIDI_CHANNELS)		return;	if (!ctl.trace_playing)		return;	semaphore_P(semid);	Panel->channel[ch].expression = val;	ctl_channel_note(ch, Panel->cnote[ch], Panel->cvel[ch]);	semaphore_V(semid);}static void ctl_panning(int ch, int val){        if(ch >= MAX_TK_MIDI_CHANNELS)		return;	if (!ctl.trace_playing)		return;	semaphore_P(semid);	Panel->channel[ch].panning = val;	Panel->c_flags[ch] |= FLAG_PAN;	semaphore_V(semid);}static void ctl_sustain(int ch, int val){        if(ch >= MAX_TK_MIDI_CHANNELS)		return;	if (!ctl.trace_playing)		return;	semaphore_P(semid);	Panel->channel[ch].sustain = val;	Panel->c_flags[ch] |= FLAG_SUST;	semaphore_V(semid);}/*ARGSUSED*/static void ctl_pitch_bend(int channel, int val){/*        if(ch >= MAX_TK_MIDI_CHANNELS)		return;	if (!ctl.trace_playing)		return;	semaphore_P(semid);	Panel->channel[ch].pitch_bend = val;	Panel->c_flags[ch] |= FLAG_BENDT;	semaphore_V(semid);*/}static void ctl_lyric(int lyricid){    char *lyric;    lyric = event2string(lyricid);    if(lyric != NULL)    {	if(lyric[0] == ME_KARAOKE_LYRIC)	{	    if(lyric[1] == '/' || lyric[1] == '\\')	    {		k_pipe_printf("CMSG %d", CMSG_TEXT);		k_pipe_puts("");		k_pipe_printf("LYRC %d", CMSG_TEXT);		k_pipe_printf("%s", lyric + 2);	    }	    else if(lyric[1] == '@')	    {		if(lyric[2] == 'L')		{		    k_pipe_printf("CMSG %d", CMSG_TEXT);		    k_pipe_printf("Language: %s", lyric + 3);		}		else if(lyric[2] == 'T')		{		    k_pipe_printf("CMSG %d", CMSG_TEXT);		    k_pipe_printf("Title: %s", lyric + 3);		}		else		{		    k_pipe_printf("CMSG %d", CMSG_TEXT);		    k_pipe_printf("%s", lyric + 1);		}	    }	    else	    {		k_pipe_printf("LYRC %d", CMSG_TEXT);		k_pipe_printf("%s", lyric + 1);	    }	}	else	{	    k_pipe_printf("CMSG %d", CMSG_TEXT);	    k_pipe_printf("%s", lyric + 1);	}    }}static void ctl_reset(void){	int i;	if (!ctl.trace_playing)	{	    k_pipe_printf("RSET %d", ctl.trace_playing);	    return;	}	Panel->wait_reset = 1;	k_pipe_printf("RSET %d", ctl.trace_playing);	while(Panel->wait_reset)	    VOLATILE_TOUCH(Panel->wait_reset);	if (!ctl.trace_playing)		return;	for (i = 0; i < MAX_TK_MIDI_CHANNELS; i++) {		if(ISDRUMCHANNEL(i))		    ctl_program(i, channel[i].bank);		else		    ctl_program(i, channel[i].program);		ctl_volume(i, channel[i].volume);		ctl_expression(i, channel[i].expression);		ctl_panning(i, channel[i].panning);		ctl_sustain(i, channel[i].sustain);		if(channel[i].pitchbend == 0x2000 &&		   channel[i].mod.val > 0)		    ctl_pitch_bend(i, -1);		else		    ctl_pitch_bend(i, channel[i].pitchbend);		ctl_channel_note(i, Panel->cnote[i], 0);	}}/***********************************************************************//* OPEN THE CONNECTION                                                *//***********************************************************************//*ARGSUSED*/static int ctl_open(int using_stdin, int using_stdout){	shm_alloc();	k_pipe_open();	if (child_pid == 0)		start_panel();	signal(SIGCHLD, get_child);	signal(SIGTERM, shm_free);	signal(SIGINT, shm_free);	signal(SIGHUP, shm_free);	ctl.opened=1;	return 0;}/* Tells the window to disapear */static void ctl_close(void){	if (ctl.opened) {		kill(child_pid, SIGTERM);		shm_free(100);		ctl.opened=0;	}}/* * Read information coming from the window in a BLOCKING way *//* commands are: PREV, NEXT, QUIT, STOP, LOAD, JUMP, VOLM */static int ctl_blocking_read(int32 *valp){	char buf[8192], *tok, *arg;	int new_volume;	int new_centiseconds;	char *args[64], **files;	int i=0, nfiles;	k_pipe_gets(buf, sizeof(buf)-1);	tok = strtok(buf, " ");	for(;;)/* Loop after pause sleeping to treat other buttons! */	{		switch (*tok) {		case 'V':			if ((arg = strtok(NULL, " ")) != NULL) {				new_volume = atoi(arg);				*valp= new_volume - amplification ;				return RC_CHANGE_VOLUME;			}			return RC_NONE;		case 'J':			if ((arg = strtok(NULL, " ")) != NULL) {				new_centiseconds = atoi(arg);				*valp= new_centiseconds*(play_mode->rate / 100) ;				return RC_JUMP;			}			return RC_NONE;		case 'Q':			return RC_QUIT;		case 'L':			return RC_LOAD_FILE;		case 'N':			return RC_NEXT;		case 'P':			/*return RC_REALLY_PREVIOUS;*/			return RC_PREVIOUS;		case 'R':			return RC_RESTART;		case 'F':			*valp=play_mode->rate;			return RC_FORWARD;		case 'B':			*valp=play_mode->rate;			return RC_BACK;		case 'X':			k_pipe_gets(buf, sizeof(buf)-1);			args[i++] = strtok(buf, " ");			while ((args[i++] = strtok(NULL, " ")) != NULL);			nfiles = --i;			files  = expand_file_archives(args, &nfiles);			k_pipe_printf("ALST %d", nfiles);			for (i=0;i<nfiles;i++)				k_pipe_puts(files[i]);			if(files != args)			    free(files);			return RC_NONE;		case 'S':			return RC_TOGGLE_PAUSE;		default:			fprintf(stderr,"UNKNOWN RC_MESSAGE `%s'\n", tok);			return RC_NONE;		}	}}/* * Read information coming from the window in a non blocking way */static int ctl_read(int32 *valp){	int num;	/* We don't wan't to lock on reading  */	num=k_pipe_read_ready();	if (num==0)		return RC_NONE;	return(ctl_blocking_read(valp));}static void ctl_pass_playing_list(int number_of_files, char *list_of_files[]){	int i=0;	char local[1000];	int command;	int32 val;	/* Pass the list to the interface */	k_pipe_printf("LIST %d", number_of_files);	for (i=0;i<number_of_files;i++)		k_pipe_puts(list_of_files[i]);	/* Ask the interface for a filename to play -> begin to play automatically */

⌨️ 快捷键说明

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