📄 smurfjam.c
字号:
/*================================================================== * smurfjam.c - TCP/IP jam with friends code * * Smurf Sound Font Editor * Copyright (C) 1999-2001 Josh Green * * Based on network server/client for ALSA sequencer (aseqnet) * ver.0.1 * * Copyright (C) 1999-2000 Takashi Iwai * * 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 or point your web browser to http://www.gnu.org. * * To contact the author of this program: * Email: Josh Green <smurf@resonance.org> * Smurf homepage: http://www.resonance.org/smurf/ *==================================================================*/#include "config.h"#ifdef ALSA_SUPPORT#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <netinet/in.h>#include <netdb.h>#include <sys/asoundlib.h>#include <getopt.h>#include <signal.h>#include <gdk/gdk.h>#include "drivers/alsa.h"#include "drivers/seq_alsa.h"#include "i18n.h"#include "smurfjam.h"#include "util.h"/* * prototypes */static void server_make_connection (void);static void flush_writebuf (void);static char *get_writebuf (int len);static int copy_local_to_remote (void);static void copy_remote_to_local(gpointer data, gint fd, GdkInputCondition cond);/* static void throw_monkey_wrench (void); */#define DEFAULT_PORT 40002 /* default TCP port number */#define MAX_BUF_EVENTS 200 /* max number of ALSA events */#define MAX_CONNECTION 10 /* max number of connections */gboolean jam_inited = FALSE;gboolean jam_server_mode;static char *readbuf;static int max_rdlen;static char *writebuf;static int cur_wrlen, max_wrlen;static int sockfd;static int netfd[MAX_CONNECTION] = {[0 ... MAX_CONNECTION-1] = -1};static int cur_connected;static int jam_seqport;/* * allocate and initialize buffers */intjam_init (void){ int i; if (jam_inited) return (OK); for (i = 0; i < MAX_CONNECTION; i++) { if (netfd[i] < 0) close (netfd[i]); } max_wrlen = MAX_BUF_EVENTS * sizeof (snd_seq_event_t); max_rdlen = MAX_BUF_EVENTS * sizeof (snd_seq_event_t); writebuf = g_malloc0 (max_wrlen); readbuf = g_malloc0 (max_rdlen); cur_wrlen = 0; if (!seq_alsa_init ()) return (FAIL); /* create a port */ jam_seqport = snd_seq_create_simple_port (seq_alsa_handle, "SmurfJam", SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC); if (jam_seqport < 0) return (logit (LogFubar | LogErrno, _("Failed to create ALSA port"))); gdk_input_add (seq_alsa_fd, GDK_INPUT_READ, (GdkInputFunction)copy_local_to_remote, NULL); log_message ("SmurfJam sequencer opened: %d:%d\n", snd_seq_client_id (seq_alsa_handle), jam_seqport); jam_inited = TRUE; return (OK);}/* * close all files */voidjam_close (void){ int i; if (!jam_inited) return; for (i = 0; i < MAX_CONNECTION; i++) { if (netfd[i] >= 0) close (netfd[i]); } if (sockfd >= 0) close (sockfd); snd_seq_delete_simple_port (seq_alsa_handle, jam_seqport); seq_alsa_close (); jam_inited = FALSE;}/* * initialize network server */intjam_server (int port){ int curstate = 1; struct sockaddr_in addr; if (!jam_init ()) return (FAIL); memset (&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons (port); sockfd = socket (AF_INET, SOCK_STREAM, 0); if (sockfd < 0) return (logit (LogFubar | LogErrno, _("Failed to create socket"))); setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)); /* the return value is ignored.. */ if (bind(sockfd, &addr, sizeof(addr)) < 0) return (logit (LogFubar | LogErrno, _("Failed to bind to socket"))); if (listen(sockfd, 5) < 0) return (logit (LogFubar | LogErrno, _("Unable to listen to socket"))); gdk_input_add (sockfd, GDK_INPUT_READ, (GdkInputFunction)server_make_connection, NULL); cur_connected = 0; jam_server_mode = TRUE; return (OK);}/* * start connection on server */static voidserver_make_connection (void){ struct sockaddr_in addr; int i; int addr_len; for (i = 0; i < MAX_CONNECTION; i++) { if (netfd[i] < 0) break; } if (i >= MAX_CONNECTION) { logit (LogWarn, "SmurfJam Server: too many connections!"); return; } memset(&addr, 0, sizeof(addr)); addr_len = sizeof(addr); netfd[i] = accept(sockfd, (struct sockaddr *)&addr, &addr_len); if (netfd[i] < 0) { logit (LogWarn, "SmurfJam Server: Failed to accept connection"); return; } gdk_input_add (netfd[i], GDK_INPUT_READ, (GdkInputFunction)copy_remote_to_local, NULL); log_message ("SmurfJam Server: accepted connection"); cur_connected++;}/* * initialize network client */intjam_client (char *server, int port){ struct sockaddr_in addr; struct hostent *host; int curstate = 1; int fd; if (!jam_init ()) return (FAIL); if ((fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) return (logit (LogFubar | LogErrno, _("Failed to create socket"))); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) return (logit (LogFubar | LogErrno, _("setsockopt failed"))); if ((host = gethostbyname(server)) == NULL) return (logit (LogFubar, _("Can't get address for host %s"), server)); addr.sin_port = htons (port); addr.sin_family = AF_INET; memcpy (&addr.sin_addr, host->h_addr, host->h_length); if (connect (fd, &addr, sizeof (addr)) < 0) return (logit (LogFubar | LogErrno, _("Failed to connect"))); log_message (_("SmurfJam Client connected")); netfd[0] = fd; cur_connected = 1; jam_server_mode = FALSE; return (OK);}/* * flush write buffer - send data to the socket */static voidflush_writebuf (void){ if (cur_wrlen) { int i; for (i = 0; i < MAX_CONNECTION; i++) { if (netfd[i] >= 0) write(netfd[i], writebuf, cur_wrlen); } cur_wrlen = 0; }}/* * get space from write buffer */static char *get_writebuf (int len){ char *buf; if (cur_wrlen + len >= max_wrlen) flush_writebuf(); buf = writebuf + cur_wrlen; cur_wrlen += len; return buf;}/* * copy events from sequencer to port(s) */static intcopy_local_to_remote (void){ int rc; snd_seq_event_t *ev; char *buf; while ((rc = snd_seq_event_input(seq_alsa_handle, &ev)) >= 0 && ev) { if (ev->type >= SND_SEQ_EVENT_CLIENT_START && ! snd_seq_ev_is_variable_type(ev)) { snd_seq_free_event(ev); continue; } if (snd_seq_ev_is_variable(ev)) { int len; len = sizeof(snd_seq_event_t) + ev->data.ext.len; buf = get_writebuf(len); memcpy(buf, ev, sizeof(snd_seq_event_t)); memcpy(buf + sizeof(snd_seq_event_t), ev->data.ext.ptr, ev->data.ext.len); } else { buf = get_writebuf(sizeof(snd_seq_event_t)); memcpy(buf, ev, sizeof(snd_seq_event_t)); } snd_seq_free_event(ev); } flush_writebuf(); return 0;}/* * copy events from a port to sequencer */static voidcopy_remote_to_local(gpointer data, gint fd, GdkInputCondition cond){ int count; char *buf; snd_seq_event_t *ev; count = read(fd, readbuf, MAX_BUF_EVENTS * sizeof(snd_seq_event_t)); buf = readbuf; if (count == 0) { fprintf(stderr, "disconnected\n"); return; } while (count > 0) { ev = (snd_seq_event_t*)buf; buf += sizeof(snd_seq_event_t); count -= sizeof(snd_seq_event_t); if (snd_seq_ev_is_variable(ev) && ev->data.ext.len > 0) { if (ev->type == SND_SEQ_EVENT_USR_VAR0) { fwrite (buf, ev->data.ext.len, 1, stdout); fflush (stdout); } ev->data.ext.ptr = buf; buf += ev->data.ext.len; count -= ev->data.ext.len; } snd_seq_ev_set_direct(ev); snd_seq_ev_set_source(ev, jam_seqport); snd_seq_ev_set_subs(ev); snd_seq_event_output(seq_alsa_handle, ev); } snd_seq_drain_output(seq_alsa_handle); return;}#if 0static voidthrow_monkey_wrench (void){ char buf[1024]; FILE *fd; size_t count; snd_seq_event_t ev; fd = fopen ("/etc/services", "r"); count = fread (buf, 1, sizeof (buf), fd); fclose (fd); ev.type = SND_SEQ_EVENT_USR_VAR0; snd_seq_ev_set_variable (&ev, count, buf); snd_seq_ev_set_direct (&ev); snd_seq_ev_set_source (&ev, 0); snd_seq_ev_set_dest (&ev, snd_seq_client_id (seq_alsa_handle), 0); snd_seq_event_output (seq_alsa_handle, &ev);#ifdef NEW_ALSA snd_seq_drain_output (seq_alsa_handle);#else snd_seq_flush_output (seq_alsa_handle);#endif}#endif#endif /* ALSA_SUPPORT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -