[proaudio] [1784] media-sound/ninjam-cclient: reformat patch to reduce file size |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/proaudio Archives
]
Revision: 1784
Author: gavlee
Date: 2010-10-26 19:39:25 +0200 (Tue, 26 Oct 2010)
Log Message:
-----------
media-sound/ninjam-cclient: reformat patch to reduce file size
Modified Paths:
--------------
trunk/overlays/proaudio/media-sound/ninjam-cclient/ChangeLog
trunk/overlays/proaudio/media-sound/ninjam-cclient/Manifest
trunk/overlays/proaudio/media-sound/ninjam-cclient/ninjam-cclient-0.01a.ebuild
Added Paths:
-----------
trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-Makefile.patch
trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-add-jack-with-fixes.patch
Removed Paths:
-------------
trunk/overlays/proaudio/media-sound/ninjam-cclient/files/add-jack-with-fixes.patch
Modified: trunk/overlays/proaudio/media-sound/ninjam-cclient/ChangeLog
===================================================================
--- trunk/overlays/proaudio/media-sound/ninjam-cclient/ChangeLog 2010-10-25 20:00:24 UTC (rev 1783)
+++ trunk/overlays/proaudio/media-sound/ninjam-cclient/ChangeLog 2010-10-26 17:39:25 UTC (rev 1784)
@@ -1,7 +1,14 @@
# ChangeLog for media-sound/ninjam-cclient
-# Copyright 1999-2007 Gentoo Foundation; Distributed under the GPL v2
+# Copyright 1999-2010 Gentoo Foundation; Distributed under the GPL v2
# $Header: $
+ 26 Oct 2010; Gavin Pryke <gavinlee303@xxxxxxxxxxxxxx>
+ ninjam-cclient-0.01a.ebuild, +files/ninjam-cclient-0.01a-Makefile.patch,
+ +files/ninjam-cclient-0.01a-add-jack-with-fixes.patch,
+ -files/add-jack-with-fixes.patch:
+ reformat jack patch to make it smaller (390K -> 14K) and add another patch
+ for the Makefile for respecting CXX/CXXFLAGS. LDFLAGS may need looking at.
+
17 Dec 2007; Thomas Kuther <gimpel@xxxxxxxxxxxxxxxx> ChangeLog:
added a changelog
Modified: trunk/overlays/proaudio/media-sound/ninjam-cclient/Manifest
===================================================================
--- trunk/overlays/proaudio/media-sound/ninjam-cclient/Manifest 2010-10-25 20:00:24 UTC (rev 1783)
+++ trunk/overlays/proaudio/media-sound/ninjam-cclient/Manifest 2010-10-26 17:39:25 UTC (rev 1784)
@@ -1,5 +1,6 @@
-AUX add-jack-with-fixes.patch 398477 RMD160 295604ba1a1c3a252cb6739e4e3b0467a4f21c02 SHA1 a3505706efbb235dacd4b1ffe8027c48acf7c176 SHA256 4beab102b77cdc0ebf7e5b0da447df9406da2ac1e729886349a08cb649b1847e
+AUX ninjam-cclient-0.01a-Makefile.patch 678 RMD160 9f923ef661f2c07ff89123424c06d4c0c69e7166 SHA1 7d2240dad50c6ebbcbb6a2fca2e3b1f904ecbfaf SHA256 d5689fdb23e51c9b6a12e480e037b6ad2923cb5699b61861264e703c76fffeee
+AUX ninjam-cclient-0.01a-add-jack-with-fixes.patch 14232 RMD160 2e29b5380e6734cfbe1d38c5a4696b44ebde2da7 SHA1 fa0d44c92b3f7420a638aa2a72edb7e571d044a9 SHA256 a0707897d4c21777f1355b9431496cd261e13f8778a558ba47b7a2fb2631f397
DIST cclient_src_v0.01a.tar.gz 73294 RMD160 5ea62b5fe386149e3ee1772e56d6f9db900f5a40 SHA1 16d0896814b09c5f395587a847c857281be79401 SHA256 52154577b6cf362240bf0e765fead3c329e62285246df2ed4cd001ce83a77a6a
-EBUILD ninjam-cclient-0.01a.ebuild 682 RMD160 2ff114b4dd0e8a669864f37b7fa4fbe9d2579ded SHA1 a6f191044eb691a71b68fbf562b89c2ff94eb3b9 SHA256 ed146edc1e7115aad562450a55a47cb7fe0af5fe7b4c1dc3f5032a69153468cb
-MISC ChangeLog 214 RMD160 4f6d73b4928970495352a288c5385140d68c05e8 SHA1 2b729e09718cd91b7ecd080613f243b067056808 SHA256 ad4d959301d976257d1cead41b46d5ec60b2552125404fa9dcf306f5d0e61b07
+EBUILD ninjam-cclient-0.01a.ebuild 943 RMD160 7d15487c1e212ee1a339f4b13539888f97667919 SHA1 7bb6b382b7077e4e29f44a1a6c1b26a61ff5dc5a SHA256 ce5f0d6acbbe2aef41ec53df3f4ec3b749c53a0a3e703948a8154b96c469a04c
+MISC ChangeLog 593 RMD160 1a60d9ffe43bde2212ed4b85927ff46d3e572665 SHA1 3b3802e365c4b1b962465cd1f7801530cc7a5a1d SHA256 6b55d46bad4fbb224bd15825149bebebb66334ea06b4125b8a1e283853bd84df
MISC metadata.xml 268 RMD160 facc07bd885f20615a1f2555069329c642e1a566 SHA1 2456bdb8a218c9d477d2d6ee4bf158de070c7be4 SHA256 96629b266b743f566c29158d4498edeeb1cd6b1f0cd9629e42d4f10b4da82f89
Deleted: trunk/overlays/proaudio/media-sound/ninjam-cclient/files/add-jack-with-fixes.patch
===================================================================
--- trunk/overlays/proaudio/media-sound/ninjam-cclient/files/add-jack-with-fixes.patch 2010-10-25 20:00:24 UTC (rev 1783)
+++ trunk/overlays/proaudio/media-sound/ninjam-cclient/files/add-jack-with-fixes.patch 2010-10-26 17:39:25 UTC (rev 1784)
@@ -1,14912 +0,0 @@
-diff -Naur ninjam-cclient-0.01a/COMPILING ninjam/COMPILING
---- ninjam-cclient-0.01a/COMPILING 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/COMPILING 2006-01-18 19:37:39.495501312 +0000
-@@ -0,0 +1,19 @@
-+On linux, install libogg, libvorbis, libasound, then do
-+
-+make
-+
-+
-+and hope things work.
-+
-+On Mac OS X, once you have the dev tools installed, install libogg and
-+libvorbis, then do:
-+
-+export MAC=1
-+make
-+
-+
-+
-+good luck!
-+
-+-Justin
-+
-diff -Naur ninjam-cclient-0.01a/Makefile ninjam/Makefile
---- ninjam-cclient-0.01a/Makefile 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/Makefile 2006-01-18 19:39:30.006701056 +0000
-@@ -0,0 +1,54 @@
-+#############################################################
-+# CPU optimization section
-+#############################################################
-+
-+OPTFLAGS = -O2
-+
-+ifdef MAC
-+OPTFLAGS += -D_MAC -mcpu=7450
-+LFLAGS = -framework coreaudio -lncurses.5 -lm
-+else
-+OPTFLAGS += -malign-double
-+LFLAGS = -lncurses -lm -ljack
-+endif
-+
-+#############################################################
-+# Basic Configuration
-+#############################################################
-+
-+# we MUST have -fomit-frame-pointer and -lm, otherwise we hate life
-+CFLAGS = $(OPTFLAGS) -s
-+# CFLAGS += -Wshadow
-+CC=gcc
-+CXX=g++
-+
-+OBJS = ./WDL/jnetlib/asyncdns.o
-+OBJS += ./WDL/jnetlib/connection.o
-+OBJS += ./WDL/jnetlib/listen.o
-+OBJS += ./WDL/jnetlib/util.o
-+OBJS += ./WDL/rng.o
-+OBJS += ./WDL/sha.o
-+OBJS += ./src/mpb.o
-+OBJS += ./src/netmsg.o
-+OBJS += ./src/njclient.o
-+
-+ifdef MAC
-+OBJS += ./src/audiostream_mac.o
-+else
-+OBJS += ./src/audiostream_jack.o
-+endif
-+
-+OBJS += ./src/njmisc.o
-+OBJS += ./src/cursesclient/cursesclient.o
-+
-+
-+CXXFLAGS = $(CFLAGS)
-+
-+default: cninjam
-+
-+cninjam: $(OBJS)
-+ $(CXX) $(CXXFLAGS) -o cninjam $(OBJS) -lpthread $(LFLAGS) -logg -lvorbis -lvorbisenc
-+
-+clean:
-+ -rm $(OBJS) cninjam
-+
-diff -Naur ninjam-cclient-0.01a/ninjam/audiostream_alsa.cpp ninjam/ninjam/audiostream_alsa.cpp
---- ninjam-cclient-0.01a/ninjam/audiostream_alsa.cpp 2005-08-30 21:49:14.000000000 +0000
-+++ ninjam/ninjam/audiostream_alsa.cpp 1970-01-01 00:00:00.000000000 +0000
-@@ -1,430 +0,0 @@
--/*
-- NINJAM - audiostream_alsa.cpp
-- Copyright (C) 2004-2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This file implements a audioStreamer that uses ALSA.
-- It only exposes the following functions:
--
-- audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc);
--
-- cfg is a string that has a list of parameter/value pairs (space delimited)
-- for the config:
-- in - input device i.e. hw:0,0
-- out - output device i.e. hw:0,0
-- srate - sample rate i.e. 48000
-- bps - bits/sample i.e. 16
-- nch - channels i.e. 2
-- bsize - block size (bytes) i.e. 2048
-- nblock - number of blocks i.e. 16
--
--
-- (everything else in this file is used internally)
--
--*/
--
--#include <stdio.h>
--#include <stdlib.h>
--#include <errno.h>
--
--#include <signal.h>
--#include <unistd.h>
--#include <fcntl.h>
--#include <pthread.h>
--
--#include <alsa/asoundlib.h>
--#include <sys/ioctl.h>
--#include <sys/soundcard.h>
--
--#include "../WDL/pcmfmtcvt.h"
--
--#include "../WDL/ptrlist.h"
--#include "audiostream.h"
--
--static void audiostream_onunder() { }
--static void audiostream_onover() { }
--
--
--
--class audioStreamer_int
--{
-- public:
-- audioStreamer_int() { m_srate=48000; m_nch=2; m_bps=16; }
-- virtual ~audioStreamer_int() { }
--
-- virtual int Read(char *buf, int len)=0; // returns 0 if blocked, < 0 if error, > 0 if data
-- virtual int Write(char *buf, int len)=0; // returns 0 on success
--
-- int m_srate, m_nch, m_bps;
--};
--
--
--
--class audioStreamer_ALSA : public audioStreamer_int
--{
-- public:
-- audioStreamer_ALSA();
-- ~audioStreamer_ALSA();
-- int Open(char *devname, int is_write, int srate, int nch, int bps, int fragsize, int nfrags, int dosleep);
--
-- int Read(char *buf, int len); // returns 0 if blocked, < 0 if error, > 0 if data
-- int Write(char *buf, int len); // returns 0 on success
-- private:
-- snd_pcm_t *pcm_handle;
-- int m_sleep;
-- int m_bufsize;
-- int m_nfrags;
-- int m_started;
--};
--
--
--
--//////////////// ALSA driver
--audioStreamer_ALSA::audioStreamer_ALSA()
--{
-- m_started=0;
-- pcm_handle=NULL;
-- m_bufsize=1000000;
--}
--
--audioStreamer_ALSA::~audioStreamer_ALSA()
--{
-- if (pcm_handle)
-- {
-- snd_pcm_drop(pcm_handle);
-- snd_pcm_close(pcm_handle);
-- }
--}
--
--int audioStreamer_ALSA::Open(char *devname, int is_write, int srate, int nch, int bps, int fragsize, int nfrags, int dosleep)
--{
-- m_sleep=dosleep;
--
-- /* Playback stream */
-- snd_pcm_stream_t stream = is_write?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE;
--
-- /* This structure contains information about */
-- /* the hardware and can be used to specify the */
-- /* configuration to be used for the PCM stream. */
-- snd_pcm_hw_params_t *hwparams;
--
-- /* Allocate the snd_pcm_hw_params_t structure on the stack. */
-- snd_pcm_hw_params_alloca(&hwparams);
--
-- if (snd_pcm_open(&pcm_handle, devname, stream, 0) < 0)
-- {
-- fprintf(stderr, "Error opening PCM device %s\n", devname);
-- return(-1);
-- }
--
-- /* Init hwparams with full configuration space */
-- if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0)
-- {
-- fprintf(stderr, "Can not configure this PCM device.\n");
-- return(-1);
-- }
--
-- if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
-- {
-- fprintf(stderr, "Error setting access.\n");
-- return(-1);
-- }
--
-- /* Set sample format */
-- m_bps=bps==32?32:bps==24?24:16;
-- if (snd_pcm_hw_params_set_format(pcm_handle, hwparams,
-- bps==32?SND_PCM_FORMAT_S32_LE:bps==24?SND_PCM_FORMAT_S24_3LE:SND_PCM_FORMAT_S16_LE) < 0) {
-- fprintf(stderr, "Error setting format.\n");
-- fprintf(stderr, "Try -bps 16, -bps 24, or -bps 32\n");
-- return(-1);
-- }
--
-- int dir=0; /* exact_rate == rate --> dir = 0 */
-- /* exact_rate < rate --> dir = -1 */
-- /* exact_rate > rate --> dir = 1 */
-- unsigned int usrate=srate;
--
-- /* Set sample rate. If the exact rate is not supported */
-- /* by the hardware, use nearest possible rate. */
-- m_srate=srate;
-- int exact_rate = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &usrate, &dir);
-- if (dir != 0)
-- {
-- fprintf(stderr, "The rate %d Hz is not supported by your hardware. Using %d Hz instead.\n", srate, exact_rate);
-- m_srate=exact_rate;
-- }
--
-- /* Set number of channels */
-- if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, nch) < 0)
-- {
-- fprintf(stderr, "Error setting channels.\n");
-- fprintf(stderr, "Try -nch 1 or -nch 2\n");
-- return(-1);
-- }
-- m_nch=nch;
--
-- int periods=m_nfrags=(is_write?nfrags:nfrags*3);
-- int periodsize=fragsize;
--
-- /* Set number of periods. Periods used to be called fragments. */
-- if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0)
-- {
-- fprintf(stderr, "Error setting periods.\n");
-- fprintf(stderr, "Try -nbufs 2 through -nbufs 16\n");
-- return(-1);
-- }
--
-- /* Set buffer size (in frames). The resulting latency is given by */
-- /* latency = periodsize * periods / (rate * bytes_per_frame) */
-- if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, m_bufsize = (periodsize * periods)/(m_nch * m_bps/8)) < 0)
-- {
-- fprintf(stderr, "Error setting buffersize.\n");
-- fprintf(stderr, "Try -bufsize 256 through -bufsize 2048\n");
-- return(-1);
-- }
--
-- /* Apply HW parameter settings to */
-- /* PCM device and prepare device */
-- if (snd_pcm_hw_params(pcm_handle, hwparams) < 0)
-- {
-- fprintf(stderr, "Error setting HW params.\n");
-- return(-1);
-- }
--
-- return 0;
--}
--
--
--int audioStreamer_ALSA::Read(char *buf, int len) // returns 0 if blocked, < 0 if error, > 0 if data
--{
-- int ret;
-- if (m_sleep >= 0)
-- {
-- struct pollfd pfds[32];
-- int cnt=snd_pcm_poll_descriptors(pcm_handle,pfds,32);
-- if (cnt>0) poll(pfds,cnt,m_sleep);
-- }
--
-- ret=snd_pcm_readi(pcm_handle, buf, len/(m_nch*(m_bps/8)));
--
-- if (ret < 0)
-- {
-- if (ret != -EAGAIN) { snd_pcm_prepare(pcm_handle); }
-- return 0;
-- }
--#if 0
-- snd_pcm_sframes_t del=0;
-- if (!snd_pcm_delay(pcm_handle,&del) && del > m_bufsize/2 /* JF>used to be /1 */)
-- {
-- audiostream_onover();
-- for (;;) if (snd_pcm_readi(pcm_handle, buf, len/(m_nch*(m_bps/8)))<0) break;
-- // we have too many samples, eat some
-- }
--#endif
--
-- return ret*m_nch*(m_bps/8);
--}
--
--
--int audioStreamer_ALSA::Write(char *buf, int len) // returns 0 on success
--{
-- snd_pcm_sframes_t del=0;
-- if (!len) return 0;
--
-- int cnt=1;
-- if (!m_started || !snd_pcm_delay(pcm_handle,&del) && del<1)
-- {
-- if (m_started) audiostream_onunder();
-- else m_started=1;
-- cnt=m_nfrags;
-- memset(buf,0,len); // reduce noise
--
-- }
--
-- while (cnt-->0)
-- {
-- int ret=snd_pcm_writei(pcm_handle, buf, len/(m_nch*(m_bps/8)));
-- if (ret < 0)
-- {
-- if (ret == -EPIPE) snd_pcm_prepare(pcm_handle);
-- return 0;
-- }
-- }
--
-- return 0;
--}
--
--
--
--
--
--//============== asio simulation shit
--//
--class audioStreamer_asiosim : public audioStreamer
--{
-- public:
-- audioStreamer_asiosim(audioStreamer_int *i, audioStreamer_int *o, int bufsize, int srate, int bps, SPLPROC proc)
-- {
-- m_splproc=proc;
-- in=i;
-- out=o;
-- m_bps=bps;
-- m_innch=m_outnch=2;
-- m_bps=bps;
-- m_srate=srate;
-- m_done=0;
-- m_buf=(char *)malloc(bufsize);
-- m_bufsize=bufsize;
--
-- m_procbuf=(float *)malloc((bufsize*64)/bps);// allocated 2x, input and output
--
--
-- // create thread
-- pthread_create(&hThread,NULL,threadProc,(void *)this);
-- }
-- ~audioStreamer_asiosim()
-- {
-- m_done=1;
--
-- // kill thread
-- pthread_join(hThread,NULL);
--
-- delete in;
-- delete out;
-- free(m_buf);
-- free(m_procbuf);
-- }
--
-- const char *GetChannelName(int idx)
-- {
-- if (idx == 0) return "Left";
-- if (idx == 1) return "Right";
-- return NULL;
-- }
--
-- private:
-- void tp();
-- static void *threadProc(void *p)
-- {
-- audioStreamer_asiosim *t=(audioStreamer_asiosim*)p;
-- t->tp();
-- return 0;
-- }
-- audioStreamer_int *in, *out;
--
-- pthread_t hThread;
-- int m_done,m_bufsize;
-- char *m_buf;
-- float *m_procbuf;
--
-- SPLPROC m_splproc;
--};
--
--void audioStreamer_asiosim::tp()
--{
-- while (!m_done)
-- {
-- int a=in->Read(m_buf,m_bufsize);
-- if (a>0)
-- {
-- int spllen=a*4/(m_bps); // a*8/m_bps/nch
-- float *inptrs[2], *outptrs[2];
-- inptrs[0]=m_procbuf;
-- inptrs[1]=m_procbuf+spllen;
-- outptrs[0]=m_procbuf+spllen*2;
-- outptrs[1]=m_procbuf+spllen*3;
--
-- pcmToFloats(m_buf,spllen,m_bps,2,inptrs[0],1);
-- pcmToFloats(m_buf+(m_bps/8),spllen,m_bps,2,inptrs[1],1);
--
-- if (m_splproc) m_splproc(inptrs,2,outptrs,2,spllen,m_srate);
--
-- floatsToPcm(outptrs[0],1,spllen,m_buf,m_bps,2);
-- floatsToPcm(outptrs[1],1,spllen,m_buf+(m_bps/8),m_bps,2);
--
-- out->Write(m_buf,a);
-- }
-- else
-- {
-- struct timespec s={0,1000*1000}; // sleep 1ms;
-- nanosleep(&s,NULL);
-- }
-- }
--}
--
--audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc)
--{
-- // todo: parse from cfg
-- char *indev="hw:0,0";
-- char *outdev="hw:0,0";
-- int srate=48000;
-- int nch=2;
-- int bps=16;
-- int fs=1024;
-- int nf=16;
--
-- while (cfg && *cfg)
-- {
-- char *p=cfg;
-- while (*p && *p != ' ') p++;
-- if (!*p) break;
-- *p++=0;
-- while (*p == ' ') p++;
-- if (!*p)
-- {
-- printf("config item '%s' has no parameter\n",cfg);
-- return 0;
-- }
--
-- if (!strcasecmp(cfg,"in")) indev=p;
-- else if (!strcasecmp(cfg,"out")) outdev=p;
-- else if (!strcasecmp(cfg,"srate")) srate=atoi(p);
-- else if (!strcasecmp(cfg,"nch")) nch=atoi(p);
-- else if (!strcasecmp(cfg,"bps")) bps=atoi(p);
-- else if (!strcasecmp(cfg,"bsize")) fs=atoi(p);
-- else if (!strcasecmp(cfg,"nblock")) nf=atoi(p);
-- else
-- {
-- printf("unknown config item '%s'\n",cfg);
-- return 0;
-- }
--
-- while (*p && *p != ' ') p++;
-- if (!*p) break;
-- *p++=0;
-- while (*p == ' ') p++;
-- cfg=p;
-- }
--
-- audioStreamer_ALSA *in=new audioStreamer_ALSA();
-- if (in->Open(indev,0,srate,nch,bps,fs,nf,-1))
-- {
-- delete in;
-- return 0;
-- }
-- audioStreamer_ALSA *out=new audioStreamer_ALSA();
-- if (out->Open(outdev,1,srate,nch,bps,fs,nf,-1))
-- {
-- delete in;
-- delete out;
-- return 0;
-- }
--
-- return new audioStreamer_asiosim(in,out,fs,srate,bps,proc);
--}
-diff -Naur ninjam-cclient-0.01a/ninjam/audiostream.h ninjam/ninjam/audiostream.h
---- ninjam-cclient-0.01a/ninjam/audiostream.h 2005-08-30 03:21:04.000000000 +0000
-+++ ninjam/ninjam/audiostream.h 1970-01-01 00:00:00.000000000 +0000
-@@ -1,72 +0,0 @@
--/*
-- NINJAM - audiostream.h
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This header is used by NINJAM clients to define an abstract audio streamer interface, as
-- well as declare functions for creating instances of these audio streamers.
--
-- On Windows, these functions are primarily called from audioconfig.cpp, and on
-- the Cocoa client the function is called from Controller.mm.
--
-- The basic structure is:
--
-- The client runs, creates an audiostreamer (below), giving it a SPLPROC, which is it's
-- own function that then in turn calls NJClient::AudioProc.
--
-- But this is just the interface declaration etc.
--
--*/
--
--#ifndef _AUDIOSTREAM_H_
--#define _AUDIOSTREAM_H_
--
--
--class audioStreamer
--{
-- public:
-- audioStreamer() { m_srate=48000; m_outnch=m_innch=2; m_bps=16; }
-- virtual ~audioStreamer() { }
--
-- virtual const char *GetChannelName(int idx)=0;
--
-- int m_srate, m_innch, m_outnch, m_bps;
--};
--
--
--typedef void (*SPLPROC)(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate);
--
--
--#ifdef _WIN32
--audioStreamer *create_audioStreamer_KS(int srate, int bps, int *nbufs, int *bufsize, SPLPROC proc);
--
--audioStreamer *create_audioStreamer_WO(int srate, int bps, int devs[2], int *nbufs, int *bufsize, SPLPROC proc);
--audioStreamer *create_audioStreamer_DS(int srate, int bps, GUID devs[2], int *nbufs, int *bufsize, SPLPROC proc);
--
--#else
--
--#ifdef _MAC
--audioStreamer *create_audioStreamer_CoreAudio(char **dev, int srate, int nch, int bps, SPLPROC proc);
--#else
--audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc);
--#endif
--
--#endif
--
--#endif
-diff -Naur ninjam-cclient-0.01a/ninjam/audiostream_mac.cpp ninjam/ninjam/audiostream_mac.cpp
---- ninjam-cclient-0.01a/ninjam/audiostream_mac.cpp 2005-08-30 03:16:06.000000000 +0000
-+++ ninjam/ninjam/audiostream_mac.cpp 1970-01-01 00:00:00.000000000 +0000
-@@ -1,474 +0,0 @@
--/*
-- NINJAM Mac OS X Clients - audiostream_mac.cpp
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This file implements the audioStream interface for CoreAudio devices.
--
--*/
--#include <stdio.h>
--#include <stdlib.h>
--#include <errno.h>
--
--#include <signal.h>
--#include <unistd.h>
--#include <fcntl.h>
--
--#include "audiostream.h"
--
--static SPLPROC _splproc;
--
--#include </System/Library/Frameworks/CoreAudio.framework/Headers/AudioHardware.h>
--
--
--class audioStreamer_CoreAudio : public audioStreamer
--{
-- public:
--
-- audioStreamer_CoreAudio();
-- ~audioStreamer_CoreAudio();
-- int Open(char **dev, int srate, int nch, int bps);
-- int Read(char *buf, int len); // returns 0 if blocked, < 0 if error, > 0 if data
-- int Write(char *buf, int len); // returns 0 on success
-- const char *GetChannelName(int idx)
-- {
-- if (idx < 0 || idx >= m_innch) return NULL;
-- static char buf[128];
-- sprintf(buf,"Channel %d",idx+1);
-- return buf;
-- }
--
--
-- private:
--
-- AudioDeviceID m_myDev_i;
-- AudioDeviceID m_myDev_o;
-- int m_started;
--
--};
--
--
--#include <sys/stat.h>
--#include <pthread.h>
--
--#include "../WDL/queue.h"
--
--static int outchtab[2]={0,1};
--
--static int g_srate;
--
--// this is a total hack until I spend the time and make a good multichannel CoreAudio implementation.
--static WDL_HeapBuf spltemp;
--
--// this takes the interleaved samples in, and puts them in their own buffers,
--// and processes, then reinterleaves
--static void onsamples_old(float *inbuf, int innch, float *outbuf, int outnch, int nsamples, int srate)
--{
-- float **inptrs = (float **)alloca(sizeof(float *)*innch);
-- int sz=nsamples*sizeof(float)*(innch+2);
-- if (spltemp.GetSize() < sz) spltemp.Resize(sz);
-- int x;
-- float *t=(float*)spltemp.Get();
-- for (x = 0; x < innch; x ++)
-- {
-- float *s=inbuf+x;
-- inptrs[x]=t;
-- int y=nsamples;
-- while (y--)
-- {
-- *t++ = *s;
-- s += innch;
-- }
-- }
-- float *outptrs[2]={t,t+nsamples};
--
-- if (_splproc) _splproc(inptrs,innch,outptrs,2,nsamples,srate);
--
-- float *p1=outptrs[0];
-- float *p2=outptrs[1];
-- x=nsamples;
-- if (outnch > 0)
-- {
-- while (x--)
-- {
-- outbuf[outchtab[0]]=*p1++;
-- if (outnch > 1) outbuf[outchtab[1]]=*p2++;
-- outbuf += outnch;
-- }
-- }
-- else
-- {
-- outnch=-outnch;
-- while (x--)
-- {
-- outbuf[0]=*p1++;
-- if (outnch > 1) outbuf[1]=*p2++;
-- outbuf += outnch;
-- }
-- }
--
--}
--
--static pthread_mutex_t m_mutex;
--static WDL_Queue m_splbuf;
--static int inchbuf=0;
--static int outchbuf=0;
--static float *ca_tmpbuf;
--static int ca_tmpbuf_size;
--
--OSStatus caIOproc(AudioDeviceID dev,
-- const AudioTimeStamp* inNow,
-- const AudioBufferList* inInputData,
-- const AudioTimeStamp* inInputTime,
-- AudioBufferList* outOutputData,
-- const AudioTimeStamp* inOutputTime,
-- void* inClientData)
--{
-- // process inInputData to outOutputData
-- if (inInputData && outOutputData)
-- {
-- int in_size=inInputData->mBuffers[inchbuf].mDataByteSize;
-- char *in=(char *)inInputData->mBuffers[inchbuf].mData;
-- int in_nch = inInputData->mBuffers[inchbuf].mNumberChannels;
--
-- int out_size=outOutputData->mBuffers[outchbuf].mDataByteSize;
-- char *out=(char *)outOutputData->mBuffers[outchbuf].mData;
-- int out_nch = outOutputData->mBuffers[outchbuf].mNumberChannels;
--
-- if (in_size*out_nch == out_size*in_nch) // faster than a divide
-- {
-- int needsize=((in_size/in_nch) * 2);
-- if (!ca_tmpbuf || ca_tmpbuf_size < needsize) ca_tmpbuf=(float*)realloc(ca_tmpbuf,ca_tmpbuf_size=needsize);
-- if (ca_tmpbuf)
-- {
-- int c=in_size/(sizeof(float)*in_nch);
-- onsamples_old((float*)in,in_nch,(float *)out,out_nch,c,g_srate);
-- }
-- }
-- }
-- return 0;
--}
--
--OSStatus caInproc(AudioDeviceID dev,
-- const AudioTimeStamp* inNow,
-- const AudioBufferList* inInputData,
-- const AudioTimeStamp* inInputTime,
-- AudioBufferList* outOutputData,
-- const AudioTimeStamp* inOutputTime,
-- void* inClientData)
--{
-- // process inInputData to outOutputData
-- if (inInputData)
-- {
-- int in_size=inInputData->mBuffers[inchbuf].mDataByteSize;
-- char *in=(char *)inInputData->mBuffers[inchbuf].mData;
-- int in_nch = inInputData->mBuffers[inchbuf].mNumberChannels;
--
-- {
-- int needsize=((in_size/in_nch) * 2);
-- if (!ca_tmpbuf || ca_tmpbuf_size < needsize) ca_tmpbuf=(float*)realloc(ca_tmpbuf,ca_tmpbuf_size=needsize);
-- if (ca_tmpbuf)
-- {
-- if (m_splbuf.GetSize() < 48000*8)
-- {
-- int c=in_size/(sizeof(float)*in_nch);
-- onsamples_old((float*)in,in_nch,(float *)ca_tmpbuf,-2,c,g_srate);
--
-- pthread_mutex_lock(&m_mutex);
--
-- m_splbuf.Add(ca_tmpbuf,needsize);
--
-- pthread_mutex_unlock(&m_mutex);
-- }
-- }
-- }
-- }
-- return 0;
--}
--
--OSStatus caOutproc(AudioDeviceID dev,
-- const AudioTimeStamp* inNow,
-- const AudioBufferList* inInputData,
-- const AudioTimeStamp* inInputTime,
-- AudioBufferList* outOutputData,
-- const AudioTimeStamp* inOutputTime,
-- void* inClientData)
--{
-- // process inInputData to outOutputData
-- if (outOutputData)
-- {
-- int out_size=outOutputData->mBuffers[outchbuf].mDataByteSize;
-- char *out=(char *)outOutputData->mBuffers[outchbuf].mData;
-- int out_nch = outOutputData->mBuffers[outchbuf].mNumberChannels;
--
-- pthread_mutex_lock(&m_mutex);
-- if (out_size < m_splbuf.Available())
-- {
-- float *fin=(float *)m_splbuf.Get();
-- float *fout=(float *)out;
-- int x,c=out_size/(sizeof(float)*out_nch);
-- for (x = 0; x < c; x ++)
-- {
-- fout[outchtab[0]]=*fin++;
-- fout[outchtab[1]]=*fin++;
-- fout += out_nch;
-- }
-- m_splbuf.Advance(out_size);
-- m_splbuf.Compact();
-- }
-- pthread_mutex_unlock(&m_mutex);
-- }
-- return 0;
--}
--
--audioStreamer_CoreAudio::audioStreamer_CoreAudio()
--{
-- m_myDev_i=0;
-- m_myDev_o=0;
-- m_started=0;
--}
--
--audioStreamer_CoreAudio::~audioStreamer_CoreAudio()
--{
-- if (m_started)
-- {
-- if (m_myDev_o != m_myDev_i)
-- {
-- AudioDeviceStop(m_myDev_i,caInproc);
-- AudioDeviceRemoveIOProc(m_myDev_i,caInproc);
-- AudioDeviceStop(m_myDev_o,caOutproc);
-- AudioDeviceRemoveIOProc(m_myDev_o,caOutproc);
-- }
-- else
-- {
-- AudioDeviceStop(m_myDev_i,caIOproc);
-- AudioDeviceRemoveIOProc(m_myDev_i,caIOproc);
-- }
-- }
--
--}
--
--
--int matchlen(const char *sub, const char *pa)
--{
-- int l=0;
-- while (*sub && *pa && toupper(*sub) == toupper(*pa)) { sub++; pa++; l++; }
-- return l;
--}
--
--int audioStreamer_CoreAudio::Open(char **dev, int srate, int nch, int bps)
--{
-- pthread_mutex_init(&m_mutex,NULL);
-- char *olddev= *dev;
-- m_srate=g_srate=srate;
-- m_bps=33;
-- m_innch=m_outnch=2;
--#ifndef AUDIOSTREAMER_NO_CONSOLEUI
-- char user_buf[512];
--#endif
--
--
-- UInt32 theSize;
-- int s = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &theSize, NULL );
-- int theNumberDevices = theSize / sizeof(AudioDeviceID);
-- if (!theNumberDevices)
-- {
-- printf("No CoreAudio devices found!\n");
-- return -1;
-- }
-- AudioDeviceID *list=(AudioDeviceID *)malloc(sizeof(AudioDeviceID)*theNumberDevices);
-- AudioHardwareGetProperty(kAudioHardwarePropertyDevices,&theSize,list);
--
--
--again:
--
-- char *indev_ptr=olddev?olddev:(char *)"";
-- char *outdev_ptr=strstr(indev_ptr,",");
-- if (outdev_ptr)
-- {
-- *outdev_ptr++=0;
-- while (*outdev_ptr == ' ') outdev_ptr++;
-- if (!*outdev_ptr) outdev_ptr=indev_ptr;
-- } else outdev_ptr=indev_ptr;
--
-- int outm=0,inm=0;
-- printf("CoreAudio device list:\n");
-- for (s = 0; s < theNumberDevices; s ++)
-- {
-- AudioDeviceID myDev;
-- myDev = list[s];
-- UInt32 os=0;
-- Boolean ow;
-- AudioDeviceGetPropertyInfo(myDev,0,0,kAudioDevicePropertyDeviceName,&os,&ow);
-- if (os > 0)
-- {
-- char *buf=(char *)malloc(os+1);
--
-- AudioDeviceGetProperty(myDev,0,0,kAudioDevicePropertyDeviceName,&os,buf);
-- if (os > 0)
-- {
-- int flags=0;
-- int i;
--
-- for (i = 0; i <2; i ++)
-- {
-- UInt32 nos=0; Boolean now;
-- AudioDeviceGetPropertyInfo(myDev,0,i,kAudioDevicePropertyStreamConfiguration,&nos,&now);
-- if (nos>=sizeof(AudioBufferList))
-- {
-- AudioBufferList *buf2=(AudioBufferList *)malloc(nos);
-- AudioDeviceGetProperty(myDev,0,i,kAudioDevicePropertyStreamConfiguration,&nos,buf2);
-- if (nos>=sizeof(AudioBufferList))
-- {
-- flags |= 1<<i;
-- }
-- free(buf2);
-- }
-- }
-- int ml=(flags & 2) ? matchlen(indev_ptr,buf) : 0;
-- if (ml > inm) { inm=ml; m_myDev_i = myDev; }
-- ml=(flags & 1) ? matchlen(outdev_ptr,buf) : 0;
-- if (ml > outm) { outm=ml; m_myDev_o = myDev; }
--
-- printf(" '%s' %s%s%s",buf,flags&2?"Input":"",flags==3?"/":"",flags&1?"Output":"");
--
-- }
--
-- printf("\n");
-- free(buf);
-- }
-- }
--
-- if (!m_myDev_i || !m_myDev_o)
-- {
-- #ifndef AUDIOSTREAMER_NO_CONSOLEUI
-- printf("Type in the beginning of the name of your sound hardware now (or leave blank for system defaults)\n");
-- printf("Note: to specify different input/output hardware, use device1, device2\n");
-- printf("Choice: ");
-- fflush(stdout);
-- user_buf[0]=0;
-- fgets(user_buf,sizeof(user_buf),stdin);
-- olddev=user_buf;
-- if (user_buf[0] && user_buf[0] != '\r' && user_buf[0] != '\n')
-- {
-- goto again;
-- }
-- #endif
-- UInt32 theSize=sizeof(AudioDeviceID);
-- if (!m_myDev_i) AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,&theSize,&m_myDev_i);
-- theSize=sizeof(AudioDeviceID);
-- if (!m_myDev_o) AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,&theSize,&m_myDev_o);
-- }
--
--
-- free(list);
--
-- int isinput;
-- for (isinput=0;isinput<2;isinput++)
-- {
-- AudioDeviceID myDev = isinput ? m_myDev_i : m_myDev_o;
--
-- UInt32 os=0;
-- Boolean ow;
-- AudioStreamBasicDescription d={0,};
-- os=sizeof(d);
-- AudioDeviceGetProperty(myDev,0,isinput,kAudioDevicePropertyStreamFormat,&os,&d);
-- if (os > 0)
-- {
-- d.mSampleRate=srate;
-- os=sizeof(d);
--// AudioDeviceSetProperty(myDev,NULL,0,isinput,kAudioDevicePropertyStreamFormat,os,&d);
-- AudioDeviceGetProperty(myDev,0,isinput,kAudioDevicePropertyStreamFormat,&os,&d);
-- if (os>0) g_srate=m_srate=(int)d.mSampleRate;
-- }
-- AudioDeviceGetPropertyInfo(myDev,0,isinput,kAudioDevicePropertyStreamConfiguration,&os,&ow);
-- if (os > 0)
-- {
-- AudioBufferList *buf=(AudioBufferList *)malloc(os);
-- AudioDeviceGetProperty(myDev,0,isinput,kAudioDevicePropertyStreamConfiguration,&os,buf);
-- int x;
-- for (x = 0; x < (int)(os/sizeof(AudioBufferList)); x ++)
-- {
-- printf(" %s Channel %d: %d buffers\n",isinput?"Input":"Output",x,(int) buf[x].mNumberBuffers);
-- int y;
-- for (y = 0; y < (int)buf[x].mNumberBuffers; y++)
-- {
-- if (buf[x].mBuffers[y].mNumberChannels)
-- printf(" buffer %d: %d channels\n",y,(int)buf[x].mBuffers[y].mNumberChannels);
-- if (y == inchbuf && !x && buf[x].mBuffers[y].mNumberChannels)
-- m_innch = buf[x].mBuffers[y].mNumberChannels;
-- }
-- break;
-- }
--
-- free(buf);
-- }
-- if (os < sizeof(AudioBufferList))
-- {
-- printf("Device has no %s buffers! Invalid device?\n",isinput ? "Input" : "Output");
-- return -1;
-- }
-- }
--
-- m_started=1;
-- if (m_myDev_o != m_myDev_i)
-- {
-- AudioDeviceAddIOProc(m_myDev_i,caInproc,(void *)this);
-- AudioDeviceAddIOProc(m_myDev_o,caOutproc,(void *)this);
--
-- AudioDeviceStart(m_myDev_i,caInproc);
-- AudioDeviceStart(m_myDev_o,caOutproc);
-- }
-- else
-- {
-- AudioDeviceAddIOProc(m_myDev_i,caIOproc,(void *)this);
-- AudioDeviceStart(m_myDev_i,caIOproc);
-- }
--
-- return 0;
--
--}
--
--int audioStreamer_CoreAudio::Read(char *buf, int len) // returns 0 if blocked, < 0 if error, > 0 if data
--{
-- struct timespec s={0,1000*1000*10}; // sleep 10ms;
-- nanosleep(&s,NULL);
--// memset(buf,0,len);
-- return 0;//len;
--}
--int audioStreamer_CoreAudio::Write(char *buf, int len) // returns 0 on success
--{
-- return 0;
--}
--
--
--audioStreamer *create_audioStreamer_CoreAudio(char **dev, int srate, int nch, int bps, SPLPROC proc)
--{
-- _splproc = proc;
-- audioStreamer_CoreAudio *audio;
--
-- audio=new audioStreamer_CoreAudio;
--
-- if (audio->Open(dev,srate,nch,bps))
-- {
-- delete audio;
-- return 0;
-- }
-- return audio;
--}
-diff -Naur ninjam-cclient-0.01a/ninjam/cursesclient/COMPILING ninjam/ninjam/cursesclient/COMPILING
---- ninjam-cclient-0.01a/ninjam/cursesclient/COMPILING 2005-08-30 22:07:40.000000000 +0000
-+++ ninjam/ninjam/cursesclient/COMPILING 1970-01-01 00:00:00.000000000 +0000
-@@ -1,19 +0,0 @@
--On linux, install libogg, libvorbis, libasound, then do
--
--make
--
--
--and hope things work.
--
--On Mac OS X, once you have the dev tools installed, install libogg and
--libvorbis, then do:
--
--export MAC=1
--make
--
--
--
--good luck!
--
---Justin
--
-diff -Naur ninjam-cclient-0.01a/ninjam/cursesclient/cursesclient.cpp ninjam/ninjam/cursesclient/cursesclient.cpp
---- ninjam-cclient-0.01a/ninjam/cursesclient/cursesclient.cpp 2005-08-30 03:59:43.000000000 +0000
-+++ ninjam/ninjam/cursesclient/cursesclient.cpp 1970-01-01 00:00:00.000000000 +0000
-@@ -1,1936 +0,0 @@
--/*
-- NINJAM Curses Client - cursesclient.cpp
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- Curses (text mode) client code. On Windows this requires the (included)
-- win32 curses emulation layer.
--
-- */
--
--#ifdef _WIN32
--#define CURSES_INSTANCE (&m_cursinst)
--#include <windows.h>
--#include "curses.h"
--#include "cursesclientinst.h"
--#define strncasecmp strnicmp
--#else
--#include <stdlib.h>
--#include <memory.h>
--#include <curses.h>
--#endif
--
--#include <stdio.h>
--#include <ctype.h>
--#include <math.h>
--#include <signal.h>
--#include <float.h>
--
--#include "../audiostream.h"
--#include "../njclient.h"
--#include "../../WDL/dirscan.h"
--#include "../../WDL/lineparse.h"
--
--#include "../njmisc.h"
--
--
--#define VALIDATE_TEXT_CHAR(thischar) ((isspace(thischar) || isgraph(thischar)) && (thischar) < 256)
--#ifdef _WIN32
--#define getch() curses_getch(CURSES_INSTANCE)
--#define erase() curses_erase(CURSES_INSTANCE)
--
--void ninjamCursesClientInstance::Run()
--{
--}
--
--
--ninjamCursesClientInstance m_cursinst;
--
--jesusonicAPI *JesusonicAPI;
--WDL_String jesusdir;
--#endif
--
--int g_chat_scroll=0;
--int curs_ypos,curs_xpos;
--int color_map[8];
--int g_ui_inchat=0;
--int g_done=0;
--int g_ui_state=0;
--int g_ui_locrename_ch;
--int g_ui_voltweakstate_channel;
--int g_need_disp_update;
--char m_lineinput_str[120];
--char m_chatinput_str[120];
--
--WDL_PtrList<char> g_chat_buffers;
--
--void addChatLine(char *src, char *text)
--{
-- while (g_chat_buffers.GetSize() > 256)
-- {
-- free(g_chat_buffers.Get(0));
-- g_chat_buffers.Delete(0);
-- }
-- WDL_String tmp;
-- if (src && *src && !strncmp(text,"/me ",4))
-- {
-- tmp.Set("* ");
-- tmp.Append(src);
-- tmp.Append(" ");
-- char *p=text+3;
-- while (*p == ' ') p++;
-- tmp.Append(p);
-- }
-- else
-- {
-- if (src&&*src)
-- {
-- tmp.Set("<");
-- tmp.Append(src);
-- tmp.Append("> ");
-- }
-- else if (src)
-- {
-- tmp.Set("*** ");
-- }
-- tmp.Append(text);
-- }
-- g_chat_buffers.Add(strdup(tmp.Get()));
-- g_chat_scroll=0;
--}
--
--WDL_String g_topic;
--
--void chatmsg_cb(int user32, NJClient *inst, char **parms, int nparms)
--{
-- if (!parms[0]) return;
--
-- if (!strcmp(parms[0],"TOPIC"))
-- {
-- if (parms[2])
-- {
-- WDL_String tmp;
-- if (parms[1] && *parms[1])
-- {
-- tmp.Set(parms[1]);
-- tmp.Append(" sets topic to: ");
-- }
-- else tmp.Set("Topic is: ");
-- tmp.Append(parms[2]);
--
-- g_topic.Set(parms[2]);
-- addChatLine("",tmp.Get());
--
-- g_need_disp_update=1;
-- }
-- }
-- else if (!strcmp(parms[0],"MSG"))
-- {
-- if (parms[1] && parms[2])
-- addChatLine(parms[1],parms[2]);
-- g_need_disp_update=1;
-- }
-- else if (!strcmp(parms[0],"PRIVMSG"))
-- {
-- if (parms[1] && parms[2])
-- {
-- WDL_String tmp;
-- tmp.Set("*");
-- tmp.Append(parms[1]);
-- tmp.Append("* ");
-- tmp.Append(parms[2]);
-- addChatLine(NULL,tmp.Get());
-- }
-- g_need_disp_update=1;
-- }
-- else if (!strcmp(parms[0],"JOIN") || !strcmp(parms[0],"PART"))
-- {
-- if (parms[1] && *parms[1])
-- {
-- WDL_String tmp(parms[1]);
-- tmp.Append(" has ");
-- tmp.Append(parms[0][0]=='P' ? "left" : "joined");
-- tmp.Append(" the server");
-- addChatLine("",tmp.Get());
-- }
-- g_need_disp_update=1;
-- }
--}
--
--
--#ifdef _WIN32
--audioStreamer *CreateConfiguredStreamer(char *inifile, int showcfg, HWND hwndParent);
--#endif
--audioStreamer *g_audio;
--NJClient *g_client;
--
--
--void audiostream_onunder() { }
--void audiostream_onover() { }
--
--int g_audio_enable=0;
--
--void audiostream_onsamples(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate)
--{
-- if (!g_audio_enable)
-- {
-- int x;
-- // clear all output buffers
-- for (x = 0; x < outnch; x ++) memset(outbuf[x],0,sizeof(float)*len);
-- return;
-- }
-- g_client->AudioProc(inbuf,innch, outbuf, outnch, len,srate);
--}
--
--
--int g_sel_x, g_sel_ypos,g_sel_ycat;
--
--#define COLORMAP(x) color_map[x]
--
--
--
--// highlights shit in []
--void highlightoutline(int line, char *str, int attrnorm, int bknorm, int attrhi, int bkhi, int attrsel, int bksel, int whl)
--{
-- int state=0;
-- int l=COLS-1;
-- int lcol=0;
-- move(line,0);
-- attrset(attrnorm);
-- bkgdset(bknorm);
--
-- while (*str && l-- > 0)
-- {
-- if (*str == ']')
-- {
-- if (state)
-- {
-- attrset(attrnorm);
-- bkgdset(bknorm);
-- state=0;
-- }
-- }
-- addch(*str);
-- if (*str == '[')
-- {
-- if (whl > 0)
-- {
-- char *tmp=strstr(str,"]");
-- if (tmp && !strstr(tmp,"["))
-- {
-- whl=0;
-- g_sel_x=lcol;
-- }
-- }
-- if (!state)
-- {
-- lcol++;
-- if (!whl--)
-- {
-- attrset(attrsel);
-- bkgdset(bksel);
-- }
-- else
-- {
-- attrset(attrhi);
-- bkgdset(bkhi);
-- }
-- state=1;
-- }
-- }
-- str++;
--
-- }
-- if (state)
-- {
-- attrset(attrnorm);
-- bkgdset(bknorm);
-- }
--
--}
--
--
--void drawstatusbar()
--{
-- if (g_ui_state) return;
-- int l,p;
-- g_client->GetPosition(&p,&l);
-- if (!l) return;
--
-- bkgdset(COLORMAP(6));
-- attrset(COLORMAP(6));
--
-- move(LINES-2,0);
-- p*=(COLS);
-- p/=l;
-- int x;
-- for (x = 0; x < COLS; x ++) addch(x <= p ? '#' : ' ');
--
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
--
-- move(curs_ypos,curs_xpos);
--}
--
--void showmainview(bool action=false, int ymove=0)
--{
-- int chat_lines=LINES/4;
-- if (chat_lines<4) chat_lines=4;
--
-- int sec1lines=2;
-- int x;
-- for (x=0;x<MAX_LOCAL_CHANNELS;x++)
-- {
-- if (g_client->EnumLocalChannels(x)<0) break;
-- sec1lines++;
-- }
--
-- int sec2lines=0;
--
-- x=0;
-- for (;;)
-- {
-- if (!g_client->GetUserState(x)) break;
--
-- int y=0;
-- for (;;)
-- {
-- if (g_client->EnumUserChannels(x,y) < 0) break;
-- sec2lines++;
-- y++;
-- }
-- x++;
-- }
-- if (!sec2lines) sec2lines=1;
--
-- if (ymove < 0)
-- {
-- if (g_sel_ypos-- <= 0)
-- {
-- if (g_sel_ycat == 1) g_sel_ypos=sec1lines-1;
-- else if (g_sel_ycat == 2) g_sel_ypos=sec2lines-1;
-- else g_sel_ypos=0;
--
-- if (g_sel_ycat>0) g_sel_ycat--;
-- }
-- }
-- else if (ymove > 0)
-- {
-- g_sel_ypos++;
-- }
--
-- if (!ymove && g_sel_ycat == 1 && g_sel_ypos >= sec2lines)
-- {
-- g_sel_ypos=sec2lines-1;
-- }
--
-- int selpos=0;
-- int selcat=0;
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
--
-- erase();
-- bkgdset(COLORMAP(1));
-- attrset(COLORMAP(1));
-- mvaddstr(0,0,"LOCAL");
-- clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
-- char linebuf[1024];
-- int linemax=LINES-2-chat_lines;
-- {
-- if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-- {
-- if (g_sel_x == 1 || g_sel_x == 3)
-- {
-- g_ui_state=1;
-- g_ui_voltweakstate_channel=g_sel_x == 1 ? -2 : -1;
-- }
-- else
-- {
-- if (g_sel_x == 0)
-- {
-- g_client->config_mastermute=!g_client->config_mastermute;
-- }
-- else
-- {
-- g_client->config_metronome_mute=!g_client->config_metronome_mute;
-- }
-- }
-- }
-- sprintf(linebuf," master: [%c]mute [",g_client->config_mastermute?'X':' ');
-- mkvolpanstr(linebuf+strlen(linebuf),g_client->config_mastervolume,g_client->config_masterpan);
--
-- sprintf(linebuf+strlen(linebuf),"] | metronome: [%c]mute [",g_client->config_metronome_mute?'X':' ');
-- mkvolpanstr(linebuf+strlen(linebuf),g_client->config_metronome,g_client->config_metronome_pan);
-- sprintf(linebuf+strlen(linebuf),"]");
--
-- highlightoutline(1,linebuf,COLORMAP(0),COLORMAP(0),
-- COLORMAP(0)|A_BOLD,COLORMAP(0),
-- COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
--// mvaddnstr(1,0,linebuf,COLS-1);
-- }
-- int ypos=2;
-- for (x=0;ypos < linemax;x++)
-- {
-- int a=g_client->EnumLocalChannels(x);
-- if (a<0) break;
-- int sch;
-- bool bc,mute;
-- float vol,pan;
-- char *name=g_client->GetLocalChannelInfo(a,&sch,NULL,&bc);
-- g_client->GetLocalChannelMonitoring(a,&vol,&pan,&mute,NULL);
--
-- if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-- {
-- if (g_sel_x == 0)
-- {
-- g_ui_state=2;
-- g_ui_locrename_ch=a;
-- strncpy(m_lineinput_str,name,sizeof(m_lineinput_str)-1);
-- }
-- else if (g_sel_x == 1)
-- {
-- // toggle active
-- g_client->SetLocalChannelInfo(a,NULL,false,0,false,0,true,bc=!bc);
-- g_client->NotifyServerOfChannelChange();
-- }
-- else if (g_sel_x == 2)
-- {
-- g_ui_state=3;
-- g_ui_locrename_ch=a;
-- }
-- else if (g_sel_x == 3)
-- {
-- // mute
-- g_client->SetLocalChannelMonitoring(a,false,0.0f,false,0.0f,true,mute=!mute,false,false);
-- }
-- else if (g_sel_x == 4)
-- {
-- //volume
-- g_ui_state=1;
-- g_ui_voltweakstate_channel=a;
-- }
--#ifdef _WIN32
-- else if (g_sel_x >= 6 && JesusonicAPI)
-- {
-- void *i=0;
-- g_client->GetLocalChannelProcessor(a,NULL,&i);
-- if (!i)
-- {
-- // start it up
-- void *p=CreateJesusInstance(a,"",g_audio->m_srate);
-- if (p) g_client->SetLocalChannelProcessor(a,jesusonic_processor,p);
-- }
-- else
-- {
-- if (g_sel_x >= 7) // kill
-- {
-- g_client->SetLocalChannelProcessor(a,NULL,NULL);
-- deleteJesusonicProc(i,a);
-- }
-- else
-- {
-- // JesusonicAPI->ui_wnd_destroy(i);
-- HWND h=JesusonicAPI->ui_wnd_gethwnd(i);
-- if (h && IsWindow(h))
-- {
-- ShowWindow(h,SW_SHOWNA);
-- SetForegroundWindow(h);
-- }
-- else
-- {
-- HWND h=JesusonicAPI->ui_wnd_create(i);
-- ShowWindow(h,SW_SHOWNA);
-- SetTimer(h,1,40,NULL);
-- SetForegroundWindow(h);
-- }
--
-- // show
-- }
-- }
-- }
--#endif
-- else if (g_sel_x >= 5)
-- {
--#ifdef _WIN32
-- void *i=0;
-- g_client->GetLocalChannelProcessor(a,NULL,&i);
-- if (i) deleteJesusonicProc(i,a);
--#endif
-- g_client->DeleteLocalChannel(a);
-- g_client->NotifyServerOfChannelChange();
-- x--;
-- action=0;
-- continue;
-- // delete
-- }
-- }
--
--
--#ifdef _WIN32
-- void *tmp;
-- g_client->GetLocalChannelProcessor(a,NULL,&tmp);
--#endif
-- char volstr[256];
-- mkvolpanstr(volstr,vol,pan);
-- const char *sname=g_audio->GetChannelName(sch);
-- if (!sname) sname="Silence";
--
-- char snamebuf[32];
-- if (strlen(sname)>16)
-- {
-- strcpy(snamebuf,"...");
-- strcat(snamebuf,sname+strlen(sname)-13);
-- sname=snamebuf;
-- }
-- sprintf(linebuf," [%s] [%c]xmit [%s] [%c]mute [%s] [del] ",name,bc?'X':' ',sname,mute?'X':' ',volstr);
--
--
--#ifdef _WIN32
-- if (JesusonicAPI)
-- {
-- sprintf(linebuf+strlen(linebuf),"[js][%c] ", tmp?'x': ' ');
-- }
--#endif
--
-- sprintf(linebuf+strlen(linebuf),
-- "<%2.1fdB>",
-- VAL2DB(g_client->GetLocalChannelPeak(a)));
--
-- highlightoutline(ypos++,linebuf,COLORMAP(0),COLORMAP(0),
-- COLORMAP(0)|A_BOLD,COLORMAP(0),
-- COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-- }
-- if (ypos < LINES-3)
-- {
-- if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-- {
-- int x;
-- for (x = 0; x < g_client->GetMaxLocalChannels(); x ++)
-- {
-- if (!g_client->GetLocalChannelInfo(x,NULL,NULL,NULL)) break;
-- }
-- if (x < g_client->GetMaxLocalChannels())
-- {
-- g_client->SetLocalChannelInfo(x,"channel",true,0,false,0,true,false);
-- g_client->NotifyServerOfChannelChange();
--
-- const char *sname=g_audio->GetChannelName(0);
-- if (!sname) sname="Silence";
--
-- char snamebuf[32];
-- if (strlen(sname)>16)
-- {
-- strcpy(snamebuf,"...");
-- strcat(snamebuf,sname+strlen(sname)-13);
-- sname=snamebuf;
-- }
--
-- char volstr[256];
-- mkvolpanstr(volstr,1.0f,0.0f);
-- sprintf(linebuf," [channel] [ ]xmit [%s] [ ]mute [%s] [del] %s<-120dB>",
-- sname,
-- volstr,
--#ifdef _WIN32
-- JesusonicAPI?"[js][ ] " :
--#endif
-- ""
--
-- );
--
-- action=false;
-- selpos++;
--
-- highlightoutline(ypos++,linebuf,COLORMAP(0),COLORMAP(0),
-- COLORMAP(0)|A_BOLD,COLORMAP(0),
-- COLORMAP(5),COLORMAP(5),g_sel_x);
--
-- }
-- }
-- if (ypos < LINES-3)
-- {
-- highlightoutline(ypos++," [new channel]",COLORMAP(0),COLORMAP(0),
-- COLORMAP(0)|A_BOLD,COLORMAP(0),
-- COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-- }
-- }
--
-- int wasadv=0;
-- if (g_sel_ycat == selcat && g_sel_ypos >= selpos)
-- {
-- wasadv=1;
-- g_sel_ycat++;
-- g_sel_ypos=0;
-- }
--
-- selpos=0;
-- selcat=1;
--
-- if (ypos < LINES-3)
-- {
-- bkgdset(COLORMAP(6));
-- attrset(COLORMAP(6));
-- mvaddnstr(ypos++,0,"REMOTE",COLS-1);
-- clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
-- }
-- int user=0;
-- x=0;
-- while (ypos < linemax)
-- {
-- if (!x) // show user info
-- {
-- char *name=g_client->GetUserState(user);
-- if (!name) break;
--
-- bkgdset(COLORMAP(4));
-- attrset(COLORMAP(4));
-- mvaddnstr(ypos++,0,name,COLS-1);
--
-- clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
--
-- }
--
-- if (ypos >= linemax) break;
--
-- int a=g_client->EnumUserChannels(user,x);
-- if (a < 0)
-- {
-- x=0;
-- user++;
-- continue;
-- }
--
-- float vol,pan;
-- bool sub,mute;
-- char *name=g_client->GetUserChannelState(user,a,&sub,&vol,&pan,&mute);
-- // show channel info
--
--
-- if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-- {
-- if (g_sel_x == 0)
-- {
-- // toggle subscribe
-- g_client->SetUserChannelState(user,a,true,sub=!sub,false,0.0f,false,0.0f,false,false,false,false);
-- }
-- else if (g_sel_x == 1)
-- {
-- // toggle mute
-- g_client->SetUserChannelState(user,a,false,false,false,0.0f,false,0.0f,true,mute=!mute,false,false);
-- }
-- else if (g_sel_x >= 2)
-- {
-- // volume
-- g_ui_state=1;
-- g_ui_voltweakstate_channel=1024+64*user+a;
-- }
-- }
--
-- char volstr[256];
-- mkvolpanstr(volstr,vol,pan);
-- sprintf(linebuf," \"%s\" [%c]recv [%c]mute [%s] <%2.1fdB>",name,sub?'X':' ',mute?'X':' ',volstr,VAL2DB(g_client->GetUserChannelPeak(user,a)));
--
-- highlightoutline(ypos++,linebuf,COLORMAP(0),COLORMAP(0),
-- COLORMAP(0)|A_BOLD,COLORMAP(0),
-- COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
--
-- x++;
--
--
-- }
--
-- if (!selpos && ypos < linemax)
-- {
-- highlightoutline(ypos++,"[no remote users]",COLORMAP(0),COLORMAP(0),
-- COLORMAP(0)|A_BOLD,COLORMAP(0),
-- COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-- }
--
-- curs_ypos=LINES-1;
-- curs_xpos=0;
--
-- if (!selpos && wasadv) g_sel_ycat++;
-- if (selpos > 0 && g_sel_ycat == selcat && g_sel_ypos >= selpos)
-- {
-- g_sel_ycat++;
-- g_sel_ypos=0;
-- }
--
-- selcat=2;
-- selpos=0;
--
-- g_ui_inchat=0;
-- if (chat_lines>=4)
-- {
-- bkgdset(COLORMAP(1));
-- attrset(COLORMAP(1));
-- mvaddnstr(LINES-2-chat_lines,0,g_topic.Get()[0]?g_topic.Get():"CHAT",COLS-1);
-- clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
--
-- int x;
-- if (g_chat_scroll > g_chat_buffers.GetSize()-(chat_lines-2)) g_chat_scroll=g_chat_buffers.GetSize()-(chat_lines-2);
-- int pos=g_chat_buffers.GetSize()-g_chat_scroll;
-- if (pos < 0) pos=0;
-- else if (pos > g_chat_buffers.GetSize()) pos=g_chat_buffers.GetSize();
--
-- for (x = 0; x < chat_lines-2; )
-- {
-- char *p;
-- if (--pos < 0 || !(p=g_chat_buffers.Get(pos))) break;
--
-- char *np=p;
-- int maxw=COLS-1;
-- while ((int)strlen(np) > maxw) np+=maxw;
--
-- while (np >= p && x < chat_lines-2)
-- {
-- mvaddnstr(LINES-2-2-x,0,np,maxw);
-- x++;
-- np-=maxw;
-- }
--
-- }
--
-- if (g_sel_ycat == selcat && g_sel_ypos == selpos++)
-- {
-- g_sel_x=0;
-- g_ui_inchat=1;
-- bkgdset(COLORMAP(2));
-- attrset(COLORMAP(2));
-- curs_ypos=LINES-2-1;
-- curs_xpos=strlen(m_chatinput_str);
-- }
-- else
-- {
-- bkgdset(COLORMAP(3));
-- attrset(COLORMAP(3));
-- }
-- mvaddstr(LINES-2-1,0,m_chatinput_str);
-- clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
-- }
--
--
-- if (g_sel_ycat == selcat && g_sel_ypos > selpos) g_sel_ypos=selpos;
--
-- if (g_ui_state==1)
-- {
-- bkgdset(COLORMAP(2));
-- attrset(COLORMAP(2));
-- mvaddnstr(LINES-2,0,"USE UP AND DOWN FOR VOLUME, LEFT AND RIGHT FOR PANNING, ENTER WHEN DONE",COLS-1);
-- clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
-- }
-- else if (g_ui_state == 3)
-- {
-- bkgdset(COLORMAP(2));
-- attrset(COLORMAP(2));
-- mvaddnstr(LINES-2,0,"USE ARROW KEYS TO SELECT THE INPUT CHANNEL, ENTER WHEN DONE",COLS-1);
-- clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
-- }
-- else drawstatusbar();
--
--
-- ypos=LINES-1;
-- sprintf(linebuf,"[QUIT NINJAM] : %s : %.1fBPM %dBPI : %dHz %dch->%dch %dbps%s",
-- g_client->GetHostName(),g_client->GetActualBPM(),g_client->GetBPI(),g_audio->m_srate,g_audio->m_innch,g_audio->m_outnch,g_audio->m_bps&~7,g_audio->m_bps&1 ? "(f)":"");
-- highlightoutline(ypos++,linebuf,COLORMAP(1),COLORMAP(1),COLORMAP(1),COLORMAP(1),COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos || g_sel_ycat != selcat) ? -1 : g_sel_x);
-- attrset(COLORMAP(1));
-- bkgdset(COLORMAP(1));
-- clrtoeol();
-- if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-- {
-- g_done++;
-- }
--
-- if (g_ui_state == 2 || g_ui_state == 4)
-- {
-- bkgdset(COLORMAP(2));
-- attrset(COLORMAP(2));
-- char *p1="RENAME CHANNEL:";
-- mvaddnstr(LINES-2,0,p1,COLS-1);
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
--
-- if ((int)strlen(p1) < COLS-2) { addch(' '); addnstr(m_lineinput_str,COLS-2-strlen(p1)); }
--
-- clrtoeol();
-- }
-- else
-- {
-- move(curs_ypos,curs_xpos);
-- }
--
--}
--
--
--
--
--void sigfunc(int sig)
--{
-- printf("Got Ctrl+C\n");
-- g_done++;
--}
--
--
--void usage(int noexit=0)
--{
--
-- printf("Usage: NINJAM hostname [options]\n"
-- "Options:\n"
-- " -user <username>\n"
-- " -pass <password>\n"
--#ifdef _WIN32
-- " -noaudiocfg\n"
-- " -jesusonic <path to jesusonic root dir>\n"
--#else
--#ifdef _MAC
-- " -audiostr device_name[,output_device_name]\n"
--#else
-- " -audiostr \"option value [option value ...]\"\n"
-- " ALSA audio options are:\n"
-- " in hw:0,0 -- set input device\n"
-- " out hw:0,0 -- set output device\n"
-- " srate 48000 -- set samplerate\n"
-- " nch 2 -- set channels\n"
-- " bps 16 -- set bits/sample\n"
-- " bsize 2048 -- set blocksize (bytes)\n"
-- " nblock 16 -- set number of blocks\n"
--#endif
--#endif
--
-- " -sessiondir <path> -- sets the session directory (default: auto)\n"
-- " -savelocalwavs -- save full quality copies of recorded files\n"
-- " -nosavesourcefiles -- don't save source files for remixing\n"
--
-- " -writewav -- writes a .wav of the jam in the session directory\n"
-- " -writeogg <bitrate> -- writes a .ogg of the jam (bitrate 64-256)..\n");
--
-- if (!noexit) exit(1);
--}
--
--int licensecallback(int user32, char *licensetext)
--{
-- /* todo, curses shit */
--
-- int isscrolled=0;
-- int linepos=0;
-- int needref=1;
-- int retval=0;
-- while (!retval)
-- {
-- if (needref)
-- {
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
--
-- erase();
-- char *tp=licensetext;
-- needref=0;
-- bkgdset(COLORMAP(6));
-- attrset(COLORMAP(6));
-- mvaddnstr(0,0,"You must agree to this license by scrolling down",COLS-1); clrtoeol();
-- mvaddnstr(1,0,"and hitting Y to connect to this server:",COLS-1); clrtoeol();
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
--
-- int x;
-- for (x = 0; x < linepos; x ++)
-- {
-- int yp=0;
-- while (*tp && *tp != '\n' && x < linepos)
-- {
-- if (yp++ >= COLS-1)
-- {
-- x++;
-- yp=0;
-- }
-- tp++;
-- }
-- if (*tp) tp++;
-- }
-- for (x = 2; x < LINES-1 && *tp; x ++)
-- {
-- move(x,0);
-- int yp=0;
-- while (*tp && *tp != '\n' && x < LINES-1)
-- {
-- if (yp++ >= COLS-1)
-- {
-- x++;
-- yp=0;
-- move(x,0);
-- }
-- addch(*tp);
-- tp++;
-- }
-- if (*tp) tp++;
-- }
-- bkgdset(COLORMAP(5));
-- attrset(COLORMAP(5));
--
-- if (*tp)
-- {
-- mvaddstr(LINES-1,0,"Use the arrows or pagedown to scroll down");
-- clrtoeol();
-- isscrolled=0;
-- }
-- else
-- {
-- mvaddstr(LINES-1,0,"Hit Y to agree");
-- clrtoeol();
-- isscrolled=1;
-- }
-- bkgdset(COLORMAP(0));
-- attrset(COLORMAP(0));
-- }
--
-- int a=getch();
-- switch (a)
-- {
-- case KEY_UP:
-- case KEY_PPAGE:
-- needref=1;
-- linepos -= a == KEY_UP ? 1 : 10;
-- if (linepos <0) linepos=0;
-- break;
-- case KEY_DOWN:
-- case KEY_NPAGE:
-- if (!isscrolled) linepos += a == KEY_DOWN ? 1 : 10;
-- needref=1;
-- break;
-- case 'y':
-- case 'Y':
-- if (isscrolled) retval=1;
-- break;
-- case 27:
-- retval=-1;
-- break;
-- };
--
--
--#ifdef _WIN32
-- MSG msg;
-- while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
-- {
-- TranslateMessage(&msg);
-- DispatchMessage(&msg);
-- }
-- Sleep(1);
--#else
-- struct timespec ts={0,1000*1000};
-- nanosleep(&ts,NULL);
--#endif
--
-- }
--
-- showmainview();
-- return retval>0;
--}
--
--int main(int argc, char **argv)
--{
-- char *parmuser=NULL;
-- char *parmpass=NULL;
-- WDL_String sessiondir;
-- int sessionspec=0;
-- int nolog=0,nowav=1,writeogg=0,g_nssf=0;
--
-- printf("NINJAM v0.01a ALPHA curses client, compiled " __DATE__ " at " __TIME__ "\nCopyright (C) 2004-2005 Cockos, Inc.\n\n");
-- char *audioconfigstr=NULL;
-- g_client=new NJClient;
-- g_client->config_savelocalaudio=1;
-- g_client->LicenseAgreementCallback=licensecallback;
-- g_client->ChatMessage_Callback=chatmsg_cb;
--
-- char *hostname;
--
--#if 1//def _MAC
-- char hostbuf[512];
-- if (argc < 2)
-- {
-- usage(1);
-- printf("(no command line options specified, using interactive mode!)\n\n\nHost to connect to: ");
-- fgets(hostbuf,sizeof(hostbuf),stdin);
-- if (hostbuf[0] && hostbuf[strlen(hostbuf)-1] == '\n') hostbuf[strlen(hostbuf)-1]=0;
-- hostname=hostbuf;
-- if (!hostbuf[0]) return 0;
-- }
--#else
-- if (argc < 2) usage();
--#endif
-- else hostname=argv[1];
--
--
--
--
-- {
-- int p;
-- for (p = 2; p < argc; p++)
-- {
-- if (!stricmp(argv[p],"-savelocalwavs"))
-- {
-- g_client->config_savelocalaudio=2;
-- }
-- else if (!stricmp(argv[p],"-nosavelocal"))
-- {
-- g_client->config_savelocalaudio=0;
-- }
-- else if (!stricmp(argv[p],"-debuglevel"))
-- {
-- if (++p >= argc) usage();
-- g_client->config_debug_level=atoi(argv[p]);
-- }
-- else if (!stricmp(argv[p],"-noaudiocfg"))
-- {
-- audioconfigstr="";
-- }
-- else if (!stricmp(argv[p],"-audiostr"))
-- {
-- if (++p >= argc) usage();
-- audioconfigstr=argv[p];
-- }
-- else if (!stricmp(argv[p],"-user"))
-- {
-- if (++p >= argc) usage();
-- parmuser=argv[p];
-- }
-- else if (!stricmp(argv[p],"-pass"))
-- {
-- if (++p >= argc) usage();
-- parmpass=argv[p];
-- }
-- else if (!stricmp(argv[p],"-writewav"))
-- {
-- nowav=0;
-- }
-- else if (!stricmp(argv[p],"-writeogg"))
-- {
-- if (++p >= argc) usage();
-- writeogg=atoi(argv[p]);
-- }
-- else if (!stricmp(argv[p],"-nowritelog"))
-- {
-- nolog++;
-- }
-- else if (!stricmp(argv[p],"-nosavesourcefiles"))
-- {
-- g_nssf++;
-- }
--#ifdef _WIN32
-- else if (!stricmp(argv[p],"-jesusonic"))
-- {
-- if (++p >= argc) usage();
-- jesusdir.Set(argv[p]);
-- }
--#endif
-- else if (!stricmp(argv[p],"-sessiondir"))
-- {
-- if (++p >= argc) usage();
-- sessiondir.Set(argv[p]);
-- sessionspec=1;
-- }
-- else usage();
-- }
-- }
--
-- if (g_nssf)
-- {
-- g_client->config_savelocalaudio=0;
-- nolog++;
-- }
--
-- char passbuf[512]="";
-- char userbuf[512]="";
-- if (!parmuser)
-- {
-- parmuser=userbuf;
-- printf("Enter username: ");
-- fgets(userbuf,sizeof(userbuf),stdin);
-- if (userbuf[0] && userbuf[strlen(userbuf)-1] == '\n') userbuf[strlen(userbuf)-1]=0;
-- if (!userbuf[0]) return 0;
-- }
-- if (!parmpass)
-- {
-- parmpass=passbuf;
-- if (strncmp(parmuser,"anonymous",9) || (parmuser[9] && parmuser[9] != ':'))
-- {
-- printf("Enter password: ");
-- fgets(passbuf,sizeof(passbuf),stdin);
-- if (passbuf[0] && passbuf[strlen(passbuf)-1] == '\n') passbuf[strlen(passbuf)-1]=0;
-- }
-- }
--
--#ifdef _WIN32
-- g_audio=CreateConfiguredStreamer("ninjam.ini", !audioconfigstr, NULL);
--
--#else
-- {
-- char *dev_name_in=audioconfigstr;
--#ifdef _MAC
-- g_audio=create_audioStreamer_CoreAudio(&dev_name_in,48000,2,16,audiostream_onsamples);
--#else
-- g_audio=create_audioStreamer_ALSA(dev_name_in,audiostream_onsamples);
--#endif
-- }
--#endif
-- if (!g_audio)
-- {
-- printf("Error opening audio!\n");
-- return 0;
-- }
-- printf("Opened at %dHz %d->%dch %dbps\n",
-- g_audio->m_srate, g_audio->m_innch, g_audio->m_outnch, g_audio->m_bps);
--
-- signal(SIGINT,sigfunc);
--
-- JNL::open_socketlib();
--
--
-- // jesusonic init
--
--#ifdef _WIN32
-- HINSTANCE jesus_hDllInst;
-- WDL_String jesusonic_configfile;
-- if (jesusdir.Get()[0])
-- {
-- jesusonic_configfile.Set(jesusdir.Get());
-- jesusonic_configfile.Append("\\cmdclient.jesusonicpreset");
-- WDL_String dll;
-- dll.Set(jesusdir.Get());
-- dll.Append("\\jesus.dll");
--
-- jesus_hDllInst = LoadLibrary(".\\jesus.dll"); // load from current dir
-- if (!jesus_hDllInst) jesus_hDllInst = LoadLibrary(dll.Get());
-- if (jesus_hDllInst)
-- {
-- *(void **)(&JesusonicAPI) = (void *)GetProcAddress(jesus_hDllInst,"JesusonicAPI");
-- if (JesusonicAPI && JesusonicAPI->ver == JESUSONIC_API_VERSION_CURRENT)
-- {
-- }
-- else JesusonicAPI = 0;
-- }
-- }
--
--#endif
-- // end jesusonic init
--
-- {
-- FILE *fp=fopen("ninjam.config","rt");
-- int x=0;
-- if (fp)
-- {
-- bool comment_state=false;
-- while (!feof(fp))
-- {
-- char buf[4096];
-- buf[0]=0;
-- fgets(buf,sizeof(buf),fp);
-- if (!buf[0]) continue;
-- if (buf[strlen(buf)-1] == '\n')
-- buf[strlen(buf)-1]=0;
-- if (!buf[0]) continue;
--
-- LineParser lp(comment_state);
--
-- lp.parse(buf);
--
-- switch (lp.gettoken_enum(0,"local\0master\0"))
-- {
-- case 0:
-- // process local line
-- if (lp.getnumtokens()>2)
-- {
-- int ch=lp.gettoken_int(1);
-- int n;
-- for (n = 2; n < lp.getnumtokens()-1; n += 2)
-- {
-- switch (lp.gettoken_enum(n,"source\0bc\0mute\0solo\0volume\0pan\0jesus\0name\0"))
-- {
-- case 0: // source
-- g_client->SetLocalChannelInfo(ch,NULL,true,lp.gettoken_int(n+1),false,0,false,false);
-- break;
-- case 1: //broadcast
-- g_client->SetLocalChannelInfo(ch,NULL,false,false,false,0,true,!!lp.gettoken_int(n+1));
-- break;
-- case 2: //mute
-- g_client->SetLocalChannelMonitoring(ch,false,false,false,false,true,!!lp.gettoken_int(n+1),false,false);
-- break;
-- case 3: //solo
-- g_client->SetLocalChannelMonitoring(ch,false,false,false,false,false,false,true,!!lp.gettoken_int(n+1));
-- break;
-- case 4: //volume
-- g_client->SetLocalChannelMonitoring(ch,true,(float)lp.gettoken_float(n+1),false,false,false,false,false,false);
-- break;
-- case 5: //pan
-- g_client->SetLocalChannelMonitoring(ch,false,false,true,(float)lp.gettoken_float(n+1),false,false,false,false);
-- break;
-- case 6: //jesus
-- if (lp.gettoken_int(n+1))
-- {
--#ifdef _WIN32
-- void *p=CreateJesusInstance(ch,"",g_audio->m_srate);
-- if (p) g_client->SetLocalChannelProcessor(ch,jesusonic_processor,p);
--#endif
-- }
-- break;
-- case 7: //name
-- g_client->SetLocalChannelInfo(ch,lp.gettoken_str(n+1),false,false,false,0,false,false);
-- break;
-- default:
-- break;
-- }
-- }
-- }
--
-- break;
-- case 1:
-- if (lp.getnumtokens()>2)
-- {
-- int n;
-- for (n = 1; n < lp.getnumtokens()-1; n += 2)
-- {
-- switch (lp.gettoken_enum(n,"mastervol\0masterpan\0metrovol\0metropan\0mastermute\0metromute\0"))
-- {
-- case 0: // mastervol
-- g_client->config_mastervolume = (float)lp.gettoken_float(n+1);
-- break;
-- case 1: // masterpan
-- g_client->config_masterpan = (float)lp.gettoken_float(n+1);
-- break;
-- case 2:
-- g_client->config_metronome = (float)lp.gettoken_float(n+1);
-- break;
-- case 3:
-- g_client->config_metronome_pan = (float)lp.gettoken_float(n+1);
-- break;
-- case 4:
-- g_client->config_mastermute = !!lp.gettoken_int(n+1);
-- break;
-- case 5:
-- g_client->config_metronome_mute = !!lp.gettoken_int(n+1);
-- break;
-- default:
-- break;
-- }
-- }
-- }
-- break;
-- default:
-- break;
-- }
--
--
-- }
-- fclose(fp);
-- }
-- else // set up defaults
-- {
-- g_client->SetLocalChannelInfo(0,"channel0",true,0,false,0,true,true);
-- g_client->SetLocalChannelMonitoring(0,false,0.0f,false,0.0f,false,false,false,false);
-- }
-- }
--
-- if (!sessiondir.Get()[0])
-- {
-- char buf[512];
--
-- int cnt=0;
-- while (cnt < 16)
-- {
--#if 0 // _WIN32
-- SYSTEMTIME st;
-- GetLocalTime(&st);
-- wsprintf(buf,"%04d%02d%02d_%02d%02d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute);
--#else
-- time_t tv;
-- time(&tv);
-- struct tm *t=localtime(&tv);
-- sprintf(buf,"%04d%02d%02d_%02d%02d",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min);
--#endif
-- if (cnt)
-- wsprintf(buf+strlen(buf),"_%d",cnt);
-- strcat(buf,".ninjam");
--
--#ifdef _WIN32
-- if (CreateDirectory(buf,NULL)) break;
--#else
-- if (!mkdir(buf,0700)) break;
--#endif
--
-- cnt++;
-- }
--
-- if (cnt >= 16)
-- {
-- printf("Error creating session directory\n");
-- buf[0]=0;
-- return 0;
-- }
--
-- sessiondir.Set(buf);
-- }
-- else
--#ifdef _WIN32
-- CreateDirectory(sessiondir.Get(),NULL);
--#else
-- mkdir(sessiondir.Get(),0700);
--#endif
-- if (sessiondir.Get()[0] && sessiondir.Get()[strlen(sessiondir.Get())-1]!='\\' && sessiondir.Get()[strlen(sessiondir.Get())-1]!='/')
--#ifdef _WIN32
-- sessiondir.Append("\\");
--#else
-- sessiondir.Append("/");
--#endif
--
-- g_client->SetWorkDir(sessiondir.Get());
--
--
-- if (!nowav)
-- {
-- WDL_String wf;
-- wf.Set(sessiondir.Get());
-- wf.Append("output.wav");
-- g_client->waveWrite = new WaveWriter(wf.Get(),24,g_audio->m_outnch>1?2:1,g_audio->m_srate);
-- }
-- if (writeogg)
-- {
-- WDL_String wf;
-- wf.Set(sessiondir.Get());
-- wf.Append("output.ogg");
-- g_client->SetOggOutFile(fopen(wf.Get(),"ab"),g_audio->m_srate,g_audio->m_outnch>1?2:1,writeogg);
-- }
-- if (!nolog)
-- {
-- WDL_String lf;
-- lf.Set(sessiondir.Get());
-- lf.Append("clipsort.log");
-- g_client->SetLogFile(lf.Get());
-- }
--
-- printf("Connecting to %s...\n",hostname);
-- g_client->Connect(hostname,parmuser,parmpass);
-- g_audio_enable=1;
--
--
--
-- // go into leet curses mode now
--#ifdef _WIN32
-- initscr(0);
--#else
-- initscr();
--#endif
-- cbreak();
-- noecho();
-- nonl();
-- intrflush(stdscr,FALSE);
-- keypad(stdscr,TRUE);
-- nodelay(stdscr,TRUE);
-- raw(); // disable ctrl+C etc. no way to kill if allow quit isn't defined, yay.
--
--#ifndef _WIN32
-- ESCDELAY=0; // dont wait--at least on the console this seems to work.
--#endif
--
-- if (has_colors()) // we don't use color yet, but we could
-- {
-- start_color();
-- init_pair(1, COLOR_WHITE, COLOR_BLUE); // normal status lines
-- init_pair(2, COLOR_BLACK, COLOR_CYAN); // value
--
--#ifdef COLOR_BLUE_DIM
-- init_pair(3, COLOR_WHITE, COLOR_BLUE_DIM); // alternating shit for the effect view
-- init_pair(4, COLOR_WHITE, COLOR_RED_DIM);
--#else
--
--#if 0 // ok this aint gonna do shit for us :(
-- if (can_change_color() && init_color(COLOR_YELLOW,0,0,150) && init_color(COLOR_MAGENTA,150,0,0))
-- {
-- init_pair(3, COLOR_WHITE, COLOR_YELLOW); // alternating shit for the effect view
-- init_pair(4, COLOR_WHITE, COLOR_MAGENTA);
-- }
-- else
--#endif
--
--
--#ifdef VGA_CONSOLE
-- char *term=getenv("TERM");
-- if (term && !strcmp(term,"linux") && !ioperm(0x3C8,2,1))
-- {
-- init_pair(3, COLOR_WHITE, COLOR_YELLOW); // alternating shit for the effect view
-- init_pair(4, COLOR_WHITE, COLOR_MAGENTA);
-- set_pal(6,0,0,15);
-- set_pal(5,15,0,0);
-- }
-- else
--#endif
-- {
-- init_pair(3, COLOR_WHITE, COLOR_BLUE); // alternating shit for the effect view
-- init_pair(4, COLOR_WHITE, COLOR_RED);
-- }
--#endif
-- init_pair(5, COLOR_BLACK, COLOR_WHITE);
-- init_pair(6, COLOR_WHITE, COLOR_RED);
-- int x;
-- for (x = 1; x < 8; x ++)
-- color_map[x]=COLOR_PAIR(x);
--
-- }
--#ifndef _WIN32
-- else
-- {
--// color_map[1]=A_BOLD;
-- color_map[2]=A_STANDOUT;
-- color_map[5]=A_STANDOUT;
-- }
--#endif
--
-- showmainview();
-- refresh();
--
--#ifdef _WIN32
-- DWORD nextupd=GetTickCount()+250;
--#else
-- time_t nextupd=time(NULL)+1;
--#endif
--
-- while (g_client->GetStatus() >= 0 && !g_done
--#ifdef _WIN32
-- && IsWindow(CURSES_INSTANCE->cursesCtx.m_hwnd)
--#endif
--
-- )
-- {
-- if (g_client->Run())
-- {
--#ifdef _WIN32
-- MSG msg;
-- while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
-- {
-- TranslateMessage(&msg);
-- DispatchMessage(&msg);
-- }
-- Sleep(1);
--#else
-- struct timespec ts={0,1000*1000};
-- nanosleep(&ts,NULL);
--#endif
--
-- int a=getch();
--#ifdef _MAC
-- {
-- static timeval last_t;
-- static int stage;
-- timeval now;
-- gettimeofday(&now,NULL);
-- if (a != ERR || (stage &&
-- ((long long) (((now.tv_sec-last_t.tv_sec) * 1000) + ((now.tv_usec-last_t.tv_usec)/1000)))>333
--
-- ))
-- {
-- last_t = now;
-- if (!stage && a == 27) { a=ERR; stage++; }
-- else if (stage==1 && a == 79) { a=ERR; stage++; }
-- else if (stage==2 && a >= 80 && a <= 91)
-- {
-- a = KEY_F(a-79);
-- stage=0;
-- }
-- else if (stage) { a = 27; stage=0; }
-- }
-- }
-- if (a == 127) a = KEY_BACKSPACE;
-- if (a == KEY_F(7)) a = KEY_F(11);
-- if (a == KEY_F(8)) a = KEY_F(12);
--#endif
-- if (a!=ERR)
-- {
-- if (!g_ui_state) switch (a)
-- {
-- case KEY_LEFT:
-- if (g_sel_x > 0)
-- {
-- g_sel_x--;
-- showmainview();
-- }
-- break;
-- case KEY_RIGHT:
-- {
-- g_sel_x++;
-- showmainview();
-- }
-- break;
-- case KEY_UP:
-- showmainview(false,-1);
-- break;
-- case KEY_DOWN:
-- showmainview(false,1);
-- break;
-- case '\r': case ' ':
-- if (!g_ui_inchat)
-- {
-- showmainview(true);
-- break;
-- }
-- default:
-- if (g_ui_inchat)
-- {
-- switch (a)
-- {
-- case KEY_PPAGE:
-- g_chat_scroll+=LINES/4-2;
-- showmainview();
-- break;
-- case KEY_NPAGE:
-- g_chat_scroll-=LINES/4-2;
-- if (g_chat_scroll<0)g_chat_scroll=0;
-- showmainview();
-- break;
-- case '\r':
-- if (m_chatinput_str[0])
-- {
-- if (m_chatinput_str[0] == '/')
-- {
-- if (!strncasecmp(m_chatinput_str,"/me ",4))
-- {
-- g_client->ChatMessage_Send("MSG",m_chatinput_str);
-- }
-- else if (!strncasecmp(m_chatinput_str,"/topic ",7)||
-- !strncasecmp(m_chatinput_str,"/kick ",6) ||
-- !strncasecmp(m_chatinput_str,"/bpm ",5) ||
-- !strncasecmp(m_chatinput_str,"/bpi ",5)
-- ) // alias to /admin *
-- {
-- g_client->ChatMessage_Send("ADMIN",m_chatinput_str+1);
-- }
-- else if (!strncasecmp(m_chatinput_str,"/admin ",7))
-- {
-- char *p=m_chatinput_str+7;
-- while (*p == ' ') p++;
-- g_client->ChatMessage_Send("ADMIN",p);
-- }
-- else if (!strncasecmp(m_chatinput_str,"/msg ",5))
-- {
-- char *p=m_chatinput_str+5;
-- while (*p == ' ') p++;
-- char *n=p;
-- while (*p && *p != ' ') p++;
-- if (*p == ' ') *p++=0;
-- while (*p == ' ') p++;
-- if (*p)
-- {
-- g_client->ChatMessage_Send("PRIVMSG",n,p);
-- WDL_String tmp;
-- tmp.Set("-> *");
-- tmp.Append(n);
-- tmp.Append("* ");
-- tmp.Append(p);
-- addChatLine(NULL,tmp.Get());
-- }
-- else
-- {
-- addChatLine("","error: /msg requires a username and a message.");
-- }
-- }
-- else
-- {
-- addChatLine("","error: unknown command.");
-- }
-- }
-- else
-- {
-- g_client->ChatMessage_Send("MSG",m_chatinput_str);
-- }
--
--
-- m_chatinput_str[0]=0;
-- showmainview();
-- }
-- break;
-- case 27:
-- {
-- m_chatinput_str[0]=0;
-- showmainview();
-- }
-- break;
-- case KEY_BACKSPACE:
-- if (m_chatinput_str[0]) m_chatinput_str[strlen(m_chatinput_str)-1]=0;
-- showmainview();
-- break;
-- default:
-- if (VALIDATE_TEXT_CHAR(a))
-- {
-- int l=strlen(m_chatinput_str);
-- if (l < (int)sizeof(m_chatinput_str)-1) { m_chatinput_str[l]=a; m_chatinput_str[l+1]=0; }
-- showmainview();
-- }
-- break;
-- }
-- }
-- break;
-- }
-- else if (g_ui_state == 1)
-- {
-- switch (a)
-- {
-- case KEY_LEFT:
-- case KEY_RIGHT:
-- {
-- float pan;
-- int ok=0;
-- if (g_ui_voltweakstate_channel == -2) { ok=1; pan=(float)g_client->config_masterpan; }
-- else if (g_ui_voltweakstate_channel == -1) { pan=(float)g_client->config_metronome_pan; ok=1; }
-- else if (g_ui_voltweakstate_channel >= 1024)
-- ok=!!g_client->GetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, NULL,NULL,&pan,NULL);
-- else ok=!g_client->GetLocalChannelMonitoring(g_ui_voltweakstate_channel,NULL,&pan,NULL,NULL);
--
-- if (ok)
-- {
-- pan += a == KEY_LEFT ? -0.01f : 0.01f;
-- if (pan > 1.0f) pan=1.0f;
-- else if (pan < -1.0f) pan=-1.0f;
-- if (g_ui_voltweakstate_channel == -2) g_client->config_masterpan=pan;
-- else if (g_ui_voltweakstate_channel == -1) g_client->config_metronome_pan=pan;
-- else if (g_ui_voltweakstate_channel>=1024)
-- g_client->SetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, false,false,false,0.0f,true,pan,false,false,false,false);
-- else
-- g_client->SetLocalChannelMonitoring(g_ui_voltweakstate_channel,false,0.0f,true,pan,false,false,false,false);
-- showmainview();
-- }
-- }
-- break;
-- case KEY_PPAGE:
-- case KEY_UP:
-- case KEY_NPAGE:
-- case KEY_DOWN:
-- {
-- float vol;
-- int ok=0;
-- if (g_ui_voltweakstate_channel == -2) { ok=1; vol=(float)g_client->config_mastervolume; }
-- else if (g_ui_voltweakstate_channel == -1) { vol=(float)g_client->config_metronome; ok=1; }
-- else if (g_ui_voltweakstate_channel >= 1024)
-- ok=!!g_client->GetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, NULL,&vol,NULL,NULL,NULL);
-- else ok=!g_client->GetLocalChannelMonitoring(g_ui_voltweakstate_channel,&vol,NULL,NULL,NULL);
--
-- if (ok)
-- {
-- vol=(float) VAL2DB(vol);
-- float sc=a == KEY_PPAGE || a == KEY_NPAGE? 4.0f : 0.5f;
-- if (a == KEY_DOWN || a == KEY_NPAGE) sc=-sc;
-- vol += sc;
-- if (vol > 20.0f) vol=20.0f;
-- else if (vol < -120.0f) vol=-120.0f;
-- vol=(float) DB2VAL(vol);
-- if (g_ui_voltweakstate_channel == -2) g_client->config_mastervolume=vol;
-- else if (g_ui_voltweakstate_channel == -1) g_client->config_metronome=vol;
-- else if (g_ui_voltweakstate_channel>=1024)
-- g_client->SetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, false,false,true,vol,false,0.0f,false,false,false,false);
-- else
-- g_client->SetLocalChannelMonitoring(g_ui_voltweakstate_channel,true,vol,false,0.0f,false,false,false,false);
-- showmainview();
-- }
-- }
-- break;
-- case 27: case '\r':
-- {
-- g_ui_state=0;
-- showmainview();
-- }
-- break;
-- }
-- }
-- else if (g_ui_state == 3)
-- {
-- switch (a)
-- {
-- case KEY_PPAGE:
-- case KEY_UP:
-- case KEY_LEFT:
-- {
-- int ch=0;
-- g_client->GetLocalChannelInfo(g_ui_locrename_ch,&ch,NULL,NULL);
-- if (ch > 0)
-- {
-- ch--;
-- g_client->SetLocalChannelInfo(g_ui_locrename_ch,NULL,true,ch,false,0,false,false);
-- g_client->NotifyServerOfChannelChange();
-- showmainview();
-- }
-- }
-- break;
-- case KEY_NPAGE:
-- case KEY_DOWN:
-- case KEY_RIGHT:
-- {
-- int ch=0;
-- g_client->GetLocalChannelInfo(g_ui_locrename_ch,&ch,NULL,NULL);
-- if (ch < g_audio->m_innch)
-- {
-- ch++;
-- g_client->SetLocalChannelInfo(g_ui_locrename_ch,NULL,true,ch,false,0,false,false);
-- g_client->NotifyServerOfChannelChange();
-- showmainview();
-- }
-- }
-- break;
--
-- case 27: case '\r':
-- {
-- g_ui_state=0;
-- showmainview();
-- }
-- break;
-- }
-- }
-- else if (g_ui_state == 2 || g_ui_state == 4)
-- {
-- switch (a)
-- {
-- case '\r':
-- if (m_lineinput_str[0])
-- {
-- if (g_ui_state == 4)
-- {
-- g_client->SetLocalChannelInfo(g_ui_locrename_ch,m_lineinput_str,false,0,false,0,false,false);
-- g_client->NotifyServerOfChannelChange();
-- }
-- }
-- g_ui_state=0;
-- showmainview();
-- break;
-- case 27:
-- {
-- g_ui_state=0;
-- showmainview();
-- }
-- break;
-- case KEY_BACKSPACE:
-- if (m_lineinput_str[0]) m_lineinput_str[strlen(m_lineinput_str)-1]=0;
-- showmainview();
-- g_ui_state=4;
-- break;
-- default:
-- if (VALIDATE_TEXT_CHAR(a) && (g_ui_state != 3 || (a >= '0' && a <= '9'))) //fucko: 9 once we have > 2ch
-- {
-- int l=strlen(m_lineinput_str);
-- if (g_ui_state == 2)
-- {
-- l=0;
-- g_ui_state=4;
-- }
--
-- if (l < (int)sizeof(m_lineinput_str)-1) { m_lineinput_str[l]=a; m_lineinput_str[l+1]=0; }
-- showmainview();
-- }
-- break;
-- }
-- }
-- }
--
-- if (g_ui_state < 2 && (g_need_disp_update||g_client->HasUserInfoChanged()||
--#ifdef _WIN32
--GetTickCount()>=nextupd
--#else
--time(NULL) >= nextupd
--#endif
--
--))
-- {
--#ifdef _WIN32
-- nextupd=GetTickCount()+1000;
--#else
-- nextupd=time(NULL)+1;
--#endif
-- g_need_disp_update=0;
-- showmainview();
-- }
-- else drawstatusbar();
-- }
--
-- }
--
-- erase();
-- refresh();
--
-- // shut down curses
-- endwin();
--
-- switch (g_client->GetStatus())
-- {
-- case NJClient::NJC_STATUS_OK:
-- break;
-- case NJClient::NJC_STATUS_INVALIDAUTH:
-- printf("ERROR: invalid login/password\n");
-- break;
-- case NJClient::NJC_STATUS_CANTCONNECT:
-- printf("ERROR: failed connecting to host\n");
-- break;
-- case NJClient::NJC_STATUS_PRECONNECT:
-- printf("ERROR: failed connect\n");
-- break;
-- case NJClient::NJC_STATUS_DISCONNECTED:
-- printf("ERROR: disconnected from host\n");
-- break;
--
-- default:
-- printf("exiting on status %d\n",g_client->GetStatus());
-- break;
-- }
-- if (g_client->GetErrorStr()[0])
-- {
-- printf("Server gave explanation: %s\n",g_client->GetErrorStr());
-- }
--
--
-- printf("Shutting down\n");
--
-- delete g_audio;
--
--
-- delete g_client->waveWrite;
-- g_client->waveWrite=0;
--
--
-- // save local channel state
-- {
-- FILE *fp=fopen("ninjam.config","wt");
-- int x=0;
-- if (fp)
-- {
-- fprintf(fp,"master mastervol %f masterpan %f metrovol %f metropan %f mastermute %d metromute %d\n",
-- g_client->config_mastervolume,g_client->config_masterpan,g_client->config_metronome,g_client->config_metronome_pan,
-- g_client->config_mastermute,g_client->config_metronome_mute);
--
--
--
-- for (x = 0;;x++)
-- {
-- int a=g_client->EnumLocalChannels(x);
-- if (a<0) break;
--
--
-- int sch=0;
-- bool bc=0;
-- void *has_jesus=0;
-- char *lcn;
-- float v=0.0f,p=0.0f;
-- bool m=0,s=0;
--
-- lcn=g_client->GetLocalChannelInfo(a,&sch,NULL,&bc);
-- g_client->GetLocalChannelMonitoring(a,&v,&p,&m,&s);
-- g_client->GetLocalChannelProcessor(a,NULL,&has_jesus);
--
-- char *ptr=lcn;
-- while (*ptr)
-- {
-- if (*ptr == '`') *ptr='\'';
-- ptr++;
-- }
-- fprintf(fp,"local %d source %d bc %d mute %d solo %d volume %f pan %f jesus %d name `%s`\n",a,sch,bc,m,s,v,p,!!has_jesus,lcn);
-- }
-- fclose(fp);
-- }
-- }
--
--
-- // delete all effects processors in g_client
-- {
-- int x=0;
-- for (x = 0;;x++)
-- {
-- int a=g_client->EnumLocalChannels(x);
-- if (a<0) break;
--#ifdef _WIN32
-- void *i=0;
-- g_client->GetLocalChannelProcessor(a,NULL,&i);
-- if (i) deleteJesusonicProc(i,a);
-- g_client->SetLocalChannelProcessor(a,NULL,NULL);
--#endif
-- }
-- }
--
--
-- delete g_client;
--
--
--#ifdef _WIN32
-- ///// jesusonic stuff
-- if (jesus_hDllInst) FreeLibrary(jesus_hDllInst);
-- jesus_hDllInst=0;
-- JesusonicAPI=0;
--
--#endif
--
-- if (g_nssf)
-- {
-- int n;
-- for (n = 0; n < 16; n ++)
-- {
-- WDL_String s(sessiondir.Get());
-- char buf[32];
-- sprintf(buf,"%x",n);
-- s.Append(buf);
--
-- {
-- WDL_DirScan ds;
-- if (!ds.First(s.Get()))
-- {
-- do
-- {
-- if (ds.GetCurrentFN()[0] != '.')
-- {
-- WDL_String t;
-- ds.GetCurrentFullFN(&t);
-- unlink(t.Get());
-- }
-- }
-- while (!ds.Next());
-- }
-- }
--#ifdef _WIN32
-- RemoveDirectory(s.Get());
--#else
-- rmdir(s.Get());
--#endif
-- }
-- }
-- if (!sessionspec)
-- {
--#ifdef _WIN32
-- RemoveDirectory(sessiondir.Get());
--#else
-- rmdir(sessiondir.Get());
--#endif
--
-- }
--
-- JNL::close_socketlib();
-- return 0;
--}
-diff -Naur ninjam-cclient-0.01a/ninjam/cursesclient/Makefile ninjam/ninjam/cursesclient/Makefile
---- ninjam-cclient-0.01a/ninjam/cursesclient/Makefile 2005-08-30 21:51:32.000000000 +0000
-+++ ninjam/ninjam/cursesclient/Makefile 1970-01-01 00:00:00.000000000 +0000
-@@ -1,53 +0,0 @@
--#############################################################
--# CPU optimization section
--#############################################################
--
--OPTFLAGS = -O2
--
--ifdef MAC
--OPTFLAGS += -D_MAC -mcpu=7450
--LFLAGS = -framework coreaudio -lncurses.5 -lm
--else
--OPTFLAGS += -malign-double
--LFLAGS = -lncurses -lm -lasound
--endif
--
--#############################################################
--# Basic Configuration
--#############################################################
--
--# we MUST have -fomit-frame-pointer and -lm, otherwise we hate life
--CFLAGS = $(OPTFLAGS) -s
--# CFLAGS += -Wshadow
--CC=gcc
--CXX=g++
--
--OBJS = ../../WDL/jnetlib/asyncdns.o
--OBJS += ../../WDL/jnetlib/connection.o
--OBJS += ../../WDL/jnetlib/listen.o
--OBJS += ../../WDL/jnetlib/util.o
--OBJS += ../../WDL/rng.o
--OBJS += ../../WDL/sha.o
--OBJS += ../mpb.o
--OBJS += ../netmsg.o
--OBJS += ../njclient.o
--
--ifdef MAC
--OBJS += ../audiostream_mac.o
--else
--OBJS += ../audiostream_alsa.o
--endif
--
--OBJS += ../njmisc.o
--OBJS += cursesclient.o
--
--
--CXXFLAGS = $(CFLAGS)
--
--default: cninjam
--
--cninjam: $(OBJS)
-- $(CXX) $(CXXFLAGS) -o cninjam $(OBJS) -lpthread $(LFLAGS) -logg -lvorbis -lvorbisenc
--
--clean:
-- -rm $(OBJS) cninjam
-diff -Naur ninjam-cclient-0.01a/ninjam/mpb.cpp ninjam/ninjam/mpb.cpp
---- ninjam-cclient-0.01a/ninjam/mpb.cpp 2005-08-30 03:16:06.000000000 +0000
-+++ ninjam/ninjam/mpb.cpp 1970-01-01 00:00:00.000000000 +0000
-@@ -1,889 +0,0 @@
--/*
-- NINJAM - mpb.cpp
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This file provides implementation of Message Parser and Builder (mpb_)
-- classes for constructing and parsing Net_Messages.
--
--*/
--
--
--#ifdef _WIN32
--#include <windows.h>
--#else
--#include <stdlib.h>
--#include <memory.h>
--#endif
--
--#include "mpb.h"
--
--
--
--// MESSAGE_SERVER_AUTH_CHALLENGE
--int mpb_server_auth_challenge::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_SERVER_AUTH_CHALLENGE) return -1;
-- if (msg->get_size() < 4+4+(int)sizeof(challenge)) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
--
-- memcpy(challenge,p,sizeof(challenge));
-- p+=sizeof(challenge);
--
-- server_caps = ((int)*p++);
-- server_caps |= ((int)*p++)<<8;
-- server_caps |= ((int)*p++)<<16;
-- server_caps |= ((int)*p++)<<24;
--
-- protocol_version = ((int)*p++);
-- protocol_version |= ((int)*p++)<<8;
-- protocol_version |= ((int)*p++)<<16;
-- protocol_version |= ((int)*p++)<<24;
--
-- if (server_caps&1)
-- {
-- char *s=(char*)p;
-- while (p-(unsigned char *)msg->get_data() < msg->get_size())
-- {
-- if (!*p)
-- {
-- license_agreement=s;
-- break;
-- }
-- p++;
-- }
-- }
--
-- return 0;
--}
--
--Net_Message *mpb_server_auth_challenge::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_SERVER_AUTH_CHALLENGE);
--
-- nm->set_size(sizeof(challenge) + 8 + (license_agreement?strlen(license_agreement)+1:0));
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
--
-- memcpy(p,challenge,sizeof(challenge));
-- p+=sizeof(challenge);
--
-- int sc=server_caps;
-- if (license_agreement) sc|=1;
-- else sc&=~1;
--
-- *p++ = sc&0xff;
-- *p++ = (sc>>8)&0xff;
-- *p++ = (sc>>16)&0xff;
-- *p++ = (sc>>24)&0xff;
--
-- *p++ = protocol_version&0xff;
-- *p++ = (protocol_version>>8)&0xff;
-- *p++ = (protocol_version>>16)&0xff;
-- *p++ = (protocol_version>>24)&0xff;
--
--
-- if (license_agreement)
-- {
-- strcpy((char*)p,license_agreement);
-- p+=strlen(license_agreement);
-- *p++=0;
-- }
--
--
-- return nm;
--}
--
--
--
--// MESSAGE_SERVER_AUTH_REPLY
--int mpb_server_auth_reply::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_SERVER_AUTH_REPLY) return -1;
-- if (msg->get_size() < 1) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
--
-- flag=*p++;
-- if (msg->get_size()>1)
-- {
-- char *t=(char*)p;
-- while (p-(unsigned char *)msg->get_data() < msg->get_size() && *p) p++;
--
-- if (p-(unsigned char *)msg->get_data() < msg->get_size())
-- {
-- errmsg=t;
--
-- p++;
-- if (p-(unsigned char *)msg->get_data() < msg->get_size())
-- {
-- maxchan=*p++;
-- }
-- }
-- }
--
-- return 0;
--}
--
--Net_Message *mpb_server_auth_reply::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_SERVER_AUTH_REPLY);
--
-- nm->set_size(errmsg?strlen(errmsg)+1+1+1:1);
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
--
-- *p++=flag;
-- if (errmsg)
-- {
-- strcpy((char*)p,errmsg);
-- p+=strlen(errmsg)+1;
-- *p++ = maxchan;
-- }
--
-- return nm;
--}
--
--
--// MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY
--int mpb_server_config_change_notify::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY) return -1;
-- if (msg->get_size() < 4) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
--
-- beats_minute = *p++;
-- beats_minute |= ((int)*p++)<<8;
-- beats_interval = *p++;
-- beats_interval |= ((int)*p++)<<8;
--
-- return 0;
--}
--
--Net_Message *mpb_server_config_change_notify::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY);
--
-- nm->set_size(4);
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
--
-- *p++=beats_minute&0xff;
-- *p++=(beats_minute>>8)&0xff;
-- *p++=beats_interval&0xff;
-- *p++=(beats_interval>>8)&0xff;
--
-- return nm;
--}
--
--
--// MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY
--int mpb_server_userinfo_change_notify::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY) return -1;
-- if (msg->get_size() < 1) return 1;
--
-- m_intmsg = msg;
-- return 0;
--}
--
--Net_Message *mpb_server_userinfo_change_notify::build()
--{
-- if (m_intmsg)
-- {
-- Net_Message *n=m_intmsg;
-- m_intmsg=0;
-- return n;
-- }
--
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY);
-- nm->set_size(0);
--
-- return nm;
--}
--
--
--void mpb_server_userinfo_change_notify::build_add_rec(int isActive, int channelid,
-- short volume, int pan, int flags, char *username, char *chname)
--{
-- int size=1+ // is remove
-- 1+ // channel index
-- 2+ // volume
-- 1+ // pan
-- 1+ // flags
-- strlen(username?username:"")+1+strlen(chname?chname:"")+1;
--
-- if (!m_intmsg)
-- {
-- m_intmsg = new Net_Message;
-- m_intmsg->set_type(MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY);
-- }
-- int oldsize=m_intmsg->get_size();
-- m_intmsg->set_size(size+oldsize);
-- unsigned char *p=(unsigned char *)m_intmsg->get_data();
-- if (p)
-- {
-- p+=oldsize;
-- *p++=!!isActive;
--
-- if (channelid < 0) channelid=0;
-- else if (channelid>255)channelid=255;
-- *p++=channelid;
--
-- *p++=volume&0xff;
-- *p++=(volume>>8)&0xff;
--
-- if (pan<-128) pan=-128;
-- else if (pan>127)pan=127;
-- *p++=(unsigned char)pan;
--
-- *p++=(unsigned char)flags;
--
-- strcpy((char*)p,username);
-- p+=strlen(username)+1;
-- strcpy((char*)p,chname);
-- p+=strlen(chname)+1;
-- }
--}
--
--
--// returns offset of next item on success, or <= 0 if out of items
--int mpb_server_userinfo_change_notify::parse_get_rec(int offs, int *isActive, int *channelid, short *volume,
-- int *pan, int *flags, char **username, char **chname)
--{
-- int hdrsize=1+ // is remove
-- 1+ // channel index
-- 2+ // volume
-- 1+ // pan
-- 1; // flags
--
-- if (!m_intmsg) return 0;
-- unsigned char *p=(unsigned char *)m_intmsg->get_data();
-- int len=m_intmsg->get_size()-offs;
-- if (!p || len < hdrsize+2) return 0;
-- p+=offs;
--
-- unsigned char *hdrbuf=p;
-- char *unp;
-- char *cnp;
--
-- if (len < hdrsize+2) return 0;
-- hdrbuf=p;
-- len -= hdrsize;
-- unp=(char *)hdrbuf+hdrsize;
-- cnp=unp;
-- while (*cnp)
-- {
-- cnp++;
-- if (!len--) return 0;
-- }
-- cnp++;
-- if (!len--) return 0;
--
-- p=(unsigned char *)cnp;
-- while (*p)
-- {
-- p++;
-- if (!len--) return 0;
-- }
-- p++;
-- if (!len--) return 0;
--
-- *isActive=(int)*hdrbuf++;
-- *channelid=(int)*hdrbuf++;
-- *volume=(int)*hdrbuf++;
-- *volume |= ((int)*hdrbuf++)<<8;
-- *pan = (int) *hdrbuf++;
-- *flags = (int) *hdrbuf++;
--
-- *username = unp;
-- *chname = cnp;
--
--
-- return p - (unsigned char *)m_intmsg->get_data();
--}
--
--
--// MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN
--int mpb_server_download_interval_begin::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN) return -1;
-- if (msg->get_size() < 25+1) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
--
-- memcpy(guid,p,sizeof(guid));
-- p+=sizeof(guid);
-- estsize = (int)*p++;
-- estsize |= ((int)*p++)<<8;
-- estsize |= ((int)*p++)<<16;
-- estsize |= ((int)*p++)<<24;
-- fourcc = (unsigned int)*p++;
-- fourcc |= ((unsigned int)*p++)<<8;
-- fourcc |= ((unsigned int)*p++)<<16;
-- fourcc |= ((unsigned int)*p++)<<24;
-- chidx = (int)*p++;
-- int len=msg->get_size()-25;
--
-- username=(char *)p;
--
--
-- // validate null termination for now
-- while (len)
-- {
-- if (!*p) break;
-- p++;
-- len--;
-- }
-- if (!len) return -1;
--
-- return 0;
--}
--
--
--Net_Message *mpb_server_download_interval_begin::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN);
--
-- nm->set_size(25+strlen(username?username:"")+1);
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
--
-- memcpy(p,guid,sizeof(guid));
-- p+=sizeof(guid);
-- *p++=(unsigned char)((estsize)&0xff);
-- *p++=(unsigned char)((estsize>>8)&0xff);
-- *p++=(unsigned char)((estsize>>16)&0xff);
-- *p++=(unsigned char)((estsize>>24)&0xff);
-- *p++=(unsigned char)((fourcc)&0xff);
-- *p++=(unsigned char)((fourcc>>8)&0xff);
-- *p++=(unsigned char)((fourcc>>16)&0xff);
-- *p++=(unsigned char)((fourcc>>24)&0xff);
-- *p++=(unsigned char)((chidx)&0xff);
--
-- strcpy((char *)p,username?username:"");
--
--
-- return nm;
--}
--
--
--// MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE
--int mpb_server_download_interval_write::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE) return -1;
-- if (msg->get_size() < 17) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
--
-- memcpy(guid,p,sizeof(guid));
-- p+=sizeof(guid);
-- flags = (char)*p++;
--
-- audio_data = p;
-- audio_data_len = msg->get_size()-17;
--
-- return 0;
--}
--
--
--Net_Message *mpb_server_download_interval_write::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE);
--
-- nm->set_size(17+(audio_data?audio_data_len:0));
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
-- memcpy(p,guid,sizeof(guid));
-- p+=sizeof(guid);
-- *p++=(unsigned char) flags;
--
-- if (audio_data&&audio_data_len) memcpy(p,audio_data,audio_data_len);
--
-- return nm;
--}
--
--
--
--
--
--
--/////////////////////////////////////////////////////////////////////////
--//////////// client to server messages
--/////////////////////////////////////////////////////////////////////////
--
--
--// MESSAGE_CLIENT_AUTH_USER
--int mpb_client_auth_user::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_CLIENT_AUTH_USER) return -1;
-- if (msg->get_size() < (int)sizeof(passhash)+1) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
-- int len=msg->get_size();
--
-- memcpy(passhash,p,sizeof(passhash));
-- p+=sizeof(passhash);
-- len -= sizeof(passhash);
--
-- username=(char *)p;
-- while (*p && len>0)
-- {
-- p++;
-- len--;
-- }
-- if (!len) return 3;
-- p++;
-- len--;
--
-- if (len < 8) return 3;
--
-- client_caps = ((int)*p++);
-- client_caps |= ((int)*p++)<<8;
-- client_caps |= ((int)*p++)<<16;
-- client_caps |= ((int)*p++)<<24;
--
-- client_version = ((int)*p++);
-- client_version |= ((int)*p++)<<8;
-- client_version |= ((int)*p++)<<16;
-- client_version |= ((int)*p++)<<24;
--
-- //printf("bla (len=%d, caps=%d) decoded client version %08x\n",len,client_caps,client_version);
--
-- return 0;
--}
--
--Net_Message *mpb_client_auth_user::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_CLIENT_AUTH_USER);
--
-- nm->set_size(sizeof(passhash) + (username?strlen(username):0) + 1 + 4 + 4);
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
--
-- memcpy(p,passhash,sizeof(passhash));
-- p+=sizeof(passhash);
--
-- strcpy((char*)p,username?username:"");
-- p+=strlen(username?username:"")+1;
--
-- *p++=(client_caps&0xff);
-- *p++=(client_caps&0xff00)>>8;
-- *p++=(client_caps&0xff0000)>>16;
-- *p++=(client_caps&0xff000000)>>24;
--
-- *p++=(client_version&0xff);
-- *p++=(client_version&0xff00)>>8;
-- *p++=(client_version&0xff0000)>>16;
-- *p++=(client_version&0xff000000)>>24;
--
-- return nm;
--}
--
--
--// MESSAGE_CLIENT_SET_USERMASK
--int mpb_client_set_usermask::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_CLIENT_SET_USERMASK) return -1;
-- if (msg->get_size() < 1) return 1;
--
-- m_intmsg = msg;
-- return 0;
--}
--
--Net_Message *mpb_client_set_usermask::build()
--{
-- if (m_intmsg)
-- {
-- Net_Message *n=m_intmsg;
-- m_intmsg=0;
-- return n;
-- }
--
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_CLIENT_SET_USERMASK);
-- nm->set_size(0);
--
-- return nm;
--}
--
--
--void mpb_client_set_usermask::build_add_rec(char *username, unsigned int chflags)
--{
-- int size=4+strlen(username?username:"")+1;
--
-- if (!m_intmsg)
-- {
-- m_intmsg = new Net_Message;
-- m_intmsg->set_type(MESSAGE_CLIENT_SET_USERMASK);
-- }
-- int oldsize=m_intmsg->get_size();
-- m_intmsg->set_size(size+oldsize);
-- unsigned char *p=(unsigned char *)m_intmsg->get_data();
-- if (p)
-- {
-- p+=oldsize;
--
-- strcpy((char*)p,username);
-- p+=strlen(username)+1;
--
-- *p++=chflags&0xff;
-- *p++=(chflags>>8)&0xff;
-- *p++=(chflags>>16)&0xff;
-- *p++=(chflags>>24)&0xff;
-- }
--}
--
--
--// returns offset of next item on success, or <= 0 if out of items
--int mpb_client_set_usermask::parse_get_rec(int offs, char **username, unsigned int *chflags)
--{
-- if (!m_intmsg) return 0;
-- unsigned char *p=(unsigned char *)m_intmsg->get_data();
-- int len=m_intmsg->get_size()-offs;
-- if (!p || len < 5) return 0;
-- p+=offs;
--
-- *username=(char*)p;
-- while (*p && len > 0)
-- {
-- len--;
-- p++;
-- }
-- p++;
-- len--;
--
-- if (len<4) return -1;
--
-- *chflags = ((int)*p++);
-- *chflags |= ((int)*p++)<<8;
-- *chflags |= ((int)*p++)<<16;
-- *chflags |= ((int)*p++)<<24;
--
-- return p - (unsigned char *)m_intmsg->get_data();
--}
--
--
--// MESSAGE_CLIENT_SET_CHANNEL_INFO
--int mpb_client_set_channel_info::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_CLIENT_SET_CHANNEL_INFO) return -1;
--
-- m_intmsg = msg;
--
-- return 0;
--}
--
--Net_Message *mpb_client_set_channel_info::build()
--{
-- if (m_intmsg)
-- {
-- Net_Message *n=m_intmsg;
-- m_intmsg=0;
-- return n;
-- }
--
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_CLIENT_SET_CHANNEL_INFO);
-- nm->set_size(0);
--
-- return nm;
--}
--
--
--void mpb_client_set_channel_info::build_add_rec(char *chname, short volume, int pan, int flags)
--{
-- int size=mpisize+strlen(chname?chname:"")+1;
--
-- if (!m_intmsg)
-- {
-- m_intmsg = new Net_Message;
-- m_intmsg->set_type(MESSAGE_CLIENT_SET_CHANNEL_INFO);
-- m_intmsg->set_size(2);
-- unsigned char *p=(unsigned char*)m_intmsg->get_data();
-- if (!p) return;
-- *p++ = mpisize&0xff;
-- *p++ = (mpisize>>8)&0xff;
-- }
-- int oldsize=m_intmsg->get_size();
-- m_intmsg->set_size(size+oldsize);
-- unsigned char *p=(unsigned char *)m_intmsg->get_data();
-- if (p)
-- {
-- p+=oldsize;
--
-- strcpy((char*)p,chname);
-- p+=strlen(chname)+1;
-- if (pan < -128) pan=-128;
-- else if (pan > 127) pan=127;
-- if (mpisize>0) *p++=(volume)&0xff;
-- if (mpisize>1) *p++=(volume>>8)&0xff;
-- if (mpisize>2) *p++=(unsigned char)pan;
-- if (mpisize>3) *p++=(unsigned char)flags;
-- if (mpisize>4)
-- memset(p,0,mpisize-4);
--
-- }
--}
--
--
--// returns offset of next item on success, or <= 0 if out of items
--int mpb_client_set_channel_info::parse_get_rec(int offs, char **chname, short *volume, int *pan, int *flags)
--{
-- if (!m_intmsg) return 0;
-- unsigned char *p=(unsigned char *)m_intmsg->get_data();
-- if (!p || m_intmsg->get_size() <= 2) return 0;
-- int len=m_intmsg->get_size()-offs;
--
-- mpisize=(int)p[0] | (((int)p[1])<<8);
-- if (len < mpisize) return 0;
--
-- p+=offs+2;
--
-- *chname=(char*)p;
-- while (*p && len > 0)
-- {
-- len--;
-- p++;
-- }
-- p++;
-- len--;
--
-- if (len<mpisize) return -1;
--
-- if (mpisize>1)
-- {
-- *volume=(int)p[0];
-- *volume|=((int)p[1])<<8;
-- }
-- else *volume=0;
-- if (mpisize>2) *pan=(int)p[2];
-- else *pan=0;
-- if (mpisize>3) *flags=(int)p[3];
-- else *flags=0;
--
-- return (p+mpisize) - ((unsigned char *)m_intmsg->get_data()+2);
--}
--
--// MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN
--
--int mpb_client_upload_interval_begin::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN) return -1;
-- if (msg->get_size() < 25) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
--
-- memcpy(guid,p,sizeof(guid));
-- p+=sizeof(guid);
-- estsize = (int)*p++;
-- estsize |= ((int)*p++)<<8;
-- estsize |= ((int)*p++)<<16;
-- estsize |= ((int)*p++)<<24;
-- fourcc = (unsigned int)*p++;
-- fourcc |= ((unsigned int)*p++)<<8;
-- fourcc |= ((unsigned int)*p++)<<16;
-- fourcc |= ((unsigned int)*p++)<<24;
-- chidx = (int)*p++;
--
-- return 0;
--}
--
--
--Net_Message *mpb_client_upload_interval_begin::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN);
--
-- nm->set_size(25);
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
--
-- memcpy(p,guid,sizeof(guid));
-- p+=sizeof(guid);
-- *p++=(unsigned char)((estsize)&0xff);
-- *p++=(unsigned char)((estsize>>8)&0xff);
-- *p++=(unsigned char)((estsize>>16)&0xff);
-- *p++=(unsigned char)((estsize>>24)&0xff);
-- *p++=(unsigned char)((fourcc)&0xff);
-- *p++=(unsigned char)((fourcc>>8)&0xff);
-- *p++=(unsigned char)((fourcc>>16)&0xff);
-- *p++=(unsigned char)((fourcc>>24)&0xff);
-- *p++=(unsigned char)((chidx)&0xff);
--
--
-- return nm;
--}
--
--
--// MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE
--int mpb_client_upload_interval_write::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE) return -1;
-- if (msg->get_size() < 17) return 1;
-- unsigned char *p=(unsigned char *)msg->get_data();
-- if (!p) return 2;
--
-- memcpy(guid,p,sizeof(guid));
-- p+=sizeof(guid);
-- flags = (char)*p++;
--
-- audio_data = p;
-- audio_data_len = msg->get_size()-17;
--
-- return 0;
--}
--
--
--Net_Message *mpb_client_upload_interval_write::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE);
--
-- nm->set_size(17+(audio_data?audio_data_len:0));
--
-- unsigned char *p=(unsigned char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
-- memcpy(p,guid,sizeof(guid));
-- p+=sizeof(guid);
-- *p++=(unsigned char) flags;
--
-- if (audio_data&&audio_data_len) memcpy(p,audio_data,audio_data_len);
--
-- return nm;
--}
--
--
--/////////////////////////////////////////////////////////////////////////
--//////////// bidirectional generic messages
--/////////////////////////////////////////////////////////////////////////
--
--
--// MESSAGE_CHAT_MESSAGE
--
--int mpb_chat_message::parse(Net_Message *msg) // return 0 on success
--{
-- if (msg->get_type() != MESSAGE_CHAT_MESSAGE) return -1;
-- if (msg->get_size() < 1) return 1;
-- char *p=(char *)msg->get_data();
-- if (!p) return 2;
--
-- char *endp=(char*)msg->get_data()+msg->get_size();
--
-- unsigned int x;
-- memset(parms,0,sizeof(parms));
-- for (x = 0; x < sizeof(parms)/sizeof(parms[0]); x ++)
-- {
-- parms[x]=p;
-- while (p < endp && *p) p++;
-- p++;
-- if (p >= endp) break;
-- }
-- return x?0:3;
--}
--
--
--Net_Message *mpb_chat_message::build()
--{
-- Net_Message *nm=new Net_Message;
-- nm->set_type(MESSAGE_CHAT_MESSAGE);
--
-- unsigned int x;
-- int sz=0;
-- for (x = 0; x < sizeof(parms)/sizeof(parms[0]); x ++)
-- {
-- sz+=(parms[x]?strlen(parms[x]):0)+1;
-- }
--
-- nm->set_size(sz);
--
-- char *p=(char *)nm->get_data();
--
-- if (!p)
-- {
-- delete nm;
-- return 0;
-- }
--
-- for (x = 0; x < sizeof(parms)/sizeof(parms[0]); x ++)
-- {
-- char *sp=parms[x];
-- if (!sp) sp="";
-- strcpy(p,sp);
-- p+=strlen(sp)+1;
-- }
--
-- return nm;
--}
-\ Kein Zeilenumbruch am Dateiende.
-diff -Naur ninjam-cclient-0.01a/ninjam/mpb.h ninjam/ninjam/mpb.h
---- ninjam-cclient-0.01a/ninjam/mpb.h 2005-08-30 03:16:06.000000000 +0000
-+++ ninjam/ninjam/mpb.h 1970-01-01 00:00:00.000000000 +0000
-@@ -1,292 +0,0 @@
--/*
-- NINJAM - mpb.h
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This header provides message-type defines, as well as Message Parser and Builder (mpb_)
-- classes for constructing and parsing Net_Messages.
--
--*/
--
--
--#ifndef _MPB_H_
--#define _MPB_H_ // mpb.h, message parsing and building
--
--
--#include "netmsg.h"
--
--
--#define PROTO_VER_MIN 0x00020000
--#define PROTO_VER_MAX 0x0002ffff
--#define PROTO_VER_CUR 0x00020000
--
--
--#define MESSAGE_SERVER_AUTH_CHALLENGE 0x00
--
--class mpb_server_auth_challenge
--{
-- public:
-- mpb_server_auth_challenge() : server_caps(0), license_agreement(0), protocol_version(0) { memset(challenge,0,sizeof(challenge)); }
-- ~mpb_server_auth_challenge() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
--
-- // public data
-- unsigned char challenge[8];
-- int server_caps; // low bit is license agreement, bits 8-16 are keepalive
-- char *license_agreement;
-- int protocol_version; // version should be 1 to start.
--};
--
--#define MESSAGE_SERVER_AUTH_REPLY 0x01
--
--class mpb_server_auth_reply
--{
-- public:
-- mpb_server_auth_reply() : flag(0), errmsg(0), maxchan(32) { }
-- ~mpb_server_auth_reply() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
--
-- // public data
-- char flag; // low bit is success bit
-- char *errmsg; // if success bit is set, and this is also set, then it is the effective username of the client
-- char maxchan;
--};
--
--
--
--#define MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY 0x02
--
--class mpb_server_config_change_notify
--{
-- public:
-- mpb_server_config_change_notify() : beats_minute(120), beats_interval(32) { }
-- ~mpb_server_config_change_notify() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
--
-- // public data
-- int beats_minute; //bpm
-- int beats_interval; // beats/interval
--};
--
--
--
--#define MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY 0x03
--
--class mpb_server_userinfo_change_notify
--{
-- public:
-- mpb_server_userinfo_change_notify() : m_intmsg(0) { }
-- ~mpb_server_userinfo_change_notify() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build(); // if you call build_add_rec at all, you must do delete x->build(); to avoid a mem leak.
--
-- // public accessors
-- // pan is -128..127
-- // volume is dB gain, so 0=0dB, 10=1dB, -30=-3 dB, etc
-- // flags, &1 = no default subscribe
-- void build_add_rec(int isActive, int channelid, short volume, int pan, int flags, char *username, char *chname);
-- int parse_get_rec(int offs, int *isActive, int *channelid, short *volume, int *pan, int *flags, char **username, char **chname); // returns offset of next item on success, or <0 if out of items
--
-- private:
--
-- Net_Message *m_intmsg;
--};
--
--
--#define MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN 0x04
--class mpb_server_download_interval_begin
--{
-- public:
-- mpb_server_download_interval_begin() : estsize(0), fourcc(0), chidx(0), username(0) { memset(guid,0,sizeof(guid)); }
-- ~mpb_server_download_interval_begin() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
-- // public data
-- unsigned char guid[16];
-- int estsize;
-- unsigned int fourcc;
-- int chidx; // only 1 byte
-- char *username;
--};
--
--
--#define MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE 0x05
--class mpb_server_download_interval_write
--{
-- public:
-- mpb_server_download_interval_write() : flags(0), audio_data(0), audio_data_len(0) { memset(guid,0,sizeof(guid)); }
-- ~mpb_server_download_interval_write() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
-- // public data
-- unsigned char guid[16]; // transfer id
-- char flags; // & 1 = end
--
-- void *audio_data;
-- int audio_data_len; // not encoded in, just used internally
--};
--
--
--
--
--#define MESSAGE_CLIENT_AUTH_USER 0x80
--class mpb_client_auth_user
--{
-- public:
-- mpb_client_auth_user() : client_caps(0), client_version(0), username(0) { memset(passhash,0,sizeof(passhash)); }
-- ~mpb_client_auth_user() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
--
-- // public data
-- unsigned char passhash[20];
-- int client_caps; // low bit is agreeing to license
-- int client_version; // client version, only present if second bit of caps is there
-- // second bit should be set, otherwise server will disconnect anyway.
-- char *username;
--};
--
--
--
--#define MESSAGE_CLIENT_SET_USERMASK 0x81
--class mpb_client_set_usermask
--{
-- public:
-- mpb_client_set_usermask() : m_intmsg(0) { }
-- ~mpb_client_set_usermask() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
--
-- void build_add_rec(char *username, unsigned int chflags);
-- int parse_get_rec(int offs, char **username, unsigned int *chflags); // returns offset of next item on success, or <0 if out of items
--
-- private:
--
-- Net_Message *m_intmsg;
--};
--
--#define MESSAGE_CLIENT_SET_CHANNEL_INFO 0x82
--class mpb_client_set_channel_info
--{
-- public:
-- mpb_client_set_channel_info() : mpisize(4), m_intmsg(0) { }
-- ~mpb_client_set_channel_info() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
--
-- // pan is -128..127
-- // volume is dB gain, so 0=0dB, 10=1dB, -30=-3 dB, etc
-- // flags, &1 = no default subscribe
-- void build_add_rec(char *chname, short volume, int pan, int flags);
-- int parse_get_rec(int offs, char **chname, short *volume, int *pan, int *flags); // returns offset of next item on success, or <0 if out of items
--
-- int mpisize;
--
-- private:
--
-- Net_Message *m_intmsg;
--};
--
--
--#define MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN 0x83
--class mpb_client_upload_interval_begin
--{
-- public:
-- mpb_client_upload_interval_begin() : estsize(0), fourcc(0), chidx(0){ memset(guid,0,sizeof(guid)); }
-- ~mpb_client_upload_interval_begin() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
-- // public data
-- unsigned char guid[16];
-- int estsize;
-- unsigned int fourcc;
-- int chidx; // only 1 byte
--};
--
--
--
--// this uses the exact same message format as the server version
--#define MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE 0x84
--class mpb_client_upload_interval_write
--{
-- public:
-- mpb_client_upload_interval_write() : flags(0), audio_data(0), audio_data_len(0) { memset(guid,0,sizeof(guid)); }
-- ~mpb_client_upload_interval_write() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
-- // public data
-- unsigned char guid[16];
-- char flags; // & 1 = end
--
-- void *audio_data;
-- int audio_data_len; // not encoded in, just used internally
--};
--
--
--#define MESSAGE_CHAT_MESSAGE 0xC0
--class mpb_chat_message
--{
-- public:
-- mpb_chat_message() { memset(parms,0,sizeof(parms)); }
-- ~mpb_chat_message() { }
--
-- int parse(Net_Message *msg); // return 0 on success
-- Net_Message *build();
--
-- char *parms[5];
--
-- // currently defined client->server commands:
-- // MSG <text> - sends a message to everybody
-- // PRIVMSG username <text> - sends a private message to username
-- // TOPIC <topic> - set server topic (need permissions)
--
-- // and server->client commands:
-- // MSG <username> <text> - a message from username
-- // PRIVMSG username <text> - a private message from username
-- // TOPIC <topic> - server topic change
--};
--
--
--
--
--#endif//_MPB_H_
-diff -Naur ninjam-cclient-0.01a/ninjam/netmsg.cpp ninjam/ninjam/netmsg.cpp
---- ninjam-cclient-0.01a/ninjam/netmsg.cpp 2005-08-30 03:16:06.000000000 +0000
-+++ ninjam/ninjam/netmsg.cpp 1970-01-01 00:00:00.000000000 +0000
-@@ -1,257 +0,0 @@
--/*
-- NINJAM - netmsg.cpp
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This file provides the implementations of the Net_Messsage class, and
-- Net_Connection class (handles sending and receiving Net_Messages to
-- a JNetLib JNL_Connection).
--
--*/
--
--
--#ifdef _WIN32
--#include <windows.h>
--#else
--#include <stdlib.h>
--#include <memory.h>
--#endif
--
--#include "netmsg.h"
--
--int Net_Message::parseBytesNeeded()
--{
-- return get_size()-m_parsepos;
--}
--
--int Net_Message::parseAddBytes(void *data, int len)
--{
-- char *p=(char*)get_data();
-- if (!p) return 0;
-- if (len > parseBytesNeeded()) len = parseBytesNeeded();
-- memcpy(p+m_parsepos,data,len);
-- m_parsepos+=len;
-- return len;
--}
--
--int Net_Message::parseMessageHeader(void *data, int len) // returns bytes used, if any (or 0 if more data needed) or -1 if invalid
--{
-- unsigned char *dp=(unsigned char *)data;
-- if (len < 5) return 0;
--
-- int type=*dp++;
--
-- int size = *dp++;
-- size |= ((int)*dp++)<<8;
-- size |= ((int)*dp++)<<16;
-- size |= ((int)*dp++)<<24;
-- len -= 5;
-- if (type == MESSAGE_INVALID || size < 0 || size > NET_MESSAGE_MAX_SIZE) return -1;
--
-- m_type=type;
-- set_size(size);
--
-- m_parsepos=0;
--
-- return 5;
--}
--
--int Net_Message::makeMessageHeader(void *data) // makes message header, data should be at least 16 bytes to be safe
--{
-- if (!data) return 0;
--
-- unsigned char *dp=(unsigned char *)data;
-- *dp++ = (unsigned char) m_type;
-- int size=get_size();
-- *dp++=size&0xff; size>>=8;
-- *dp++=size&0xff; size>>=8;
-- *dp++=size&0xff; size>>=8;
-- *dp++=size&0xff;
--
-- return (dp-(unsigned char *)data);
--}
--
--
--
--Net_Message *Net_Connection::Run(int *wantsleep)
--{
-- if (!m_con || m_error) return 0;
--
-- m_con->run();
--
-- time_t now=time(NULL);
--
-- if (m_sendq.Available() > 0) m_last_send=now;
-- else if (now > m_last_send + m_keepalive)
-- {
-- Net_Message *keepalive= new Net_Message;
-- keepalive->set_type(MESSAGE_KEEPALIVE);
-- keepalive->set_size(0);
-- Send(keepalive);
-- m_last_send=now;
-- }
--
-- // handle sending
-- while (m_con->send_bytes_available()>64 && m_sendq.Available()>0)
-- {
-- Net_Message **topofq = (Net_Message **)m_sendq.Get();
--
-- if (!topofq) break;
-- Net_Message *sendm=*topofq;
-- if (sendm)
-- {
-- if (wantsleep) *wantsleep=0;
-- if (m_msgsendpos<0) // send header
-- {
-- char buf[32];
-- int hdrlen=sendm->makeMessageHeader(buf);
-- m_con->send_bytes(buf,hdrlen);
--
-- m_msgsendpos=0;
-- }
--
-- int sz=sendm->get_size()-m_msgsendpos;
-- if (sz < 1) // end of message, discard and move to next
-- {
-- sendm->releaseRef();
-- m_sendq.Advance(sizeof(Net_Message*));
-- m_msgsendpos=-1;
-- }
-- else
-- {
-- int avail=m_con->send_bytes_available();
-- if (sz > avail) sz=avail;
-- if (sz>0)
-- {
-- m_con->send_bytes((char*)sendm->get_data()+m_msgsendpos,sz);
-- m_msgsendpos+=sz;
-- }
-- }
-- }
-- else
-- {
-- m_sendq.Advance(sizeof(Net_Message*));
-- m_msgsendpos=-1;
-- }
-- }
--
-- m_sendq.Compact();
--
-- Net_Message *retv=0;
--
-- // handle receive now
-- if (!m_recvmsg)
-- {
-- m_recvmsg=new Net_Message;
-- m_recvstate=0;
-- }
--
-- while (!retv && m_con->recv_bytes_available()>0)
-- {
-- char buf[8192];
-- int bufl=m_con->peek_bytes(buf,sizeof(buf));
-- int a=0;
--
-- if (!m_recvstate)
-- {
-- a=m_recvmsg->parseMessageHeader(buf,bufl);
-- if (a<0)
-- {
-- m_error=-1;
-- break;
-- }
-- if (a==0) break;
-- m_recvstate=1;
-- }
-- int b2=m_recvmsg->parseAddBytes(buf+a,bufl-a);
--
-- m_con->recv_bytes(buf,b2+a); // dump our bytes that we used
--
-- if (m_recvmsg->parseBytesNeeded()<1)
-- {
-- retv=m_recvmsg;
-- m_recvmsg=0;
-- m_recvstate=0;
-- }
-- if (wantsleep) *wantsleep=0;
-- }
--
-- m_con->run();
--
--
-- if (retv)
-- {
-- m_last_recv=now;
-- }
-- else if (now > m_last_recv + m_keepalive*3)
-- {
-- m_error=-3;
-- }
--
-- return retv;
--}
--
--int Net_Connection::Send(Net_Message *msg)
--{
-- if (msg)
-- {
-- msg->addRef();
-- if (m_sendq.GetSize() < NET_CON_MAX_MESSAGES*(int)sizeof(Net_Message *))
-- m_sendq.Add(&msg,sizeof(Net_Message *));
-- else
-- {
-- m_error=-2;
-- msg->releaseRef(); // todo: debug message to log overrun error
-- return -1;
-- }
-- }
-- return 0;
--}
--
--int Net_Connection::GetStatus()
--{
-- if (m_error) return m_error;
-- return !m_con || m_con->get_state()<JNL_Connection::STATE_RESOLVING || m_con->get_state()>=JNL_Connection::STATE_CLOSING; // 1 if disconnected somehow
--}
--
--Net_Connection::~Net_Connection()
--{
-- Net_Message **p=(Net_Message **)m_sendq.Get();
-- if (p)
-- {
-- int n=m_sendq.Available()/sizeof(Net_Message *);
-- while (n-->0)
-- {
-- (*p)->releaseRef();
-- p++;
-- }
-- m_sendq.Advance(m_sendq.Available());
--
-- }
--
-- delete m_con;
-- delete m_recvmsg;
--
--}
--
--
--void Net_Connection::Kill(int quick)
--{
-- m_con->close();
--}
-diff -Naur ninjam-cclient-0.01a/ninjam/netmsg.h ninjam/ninjam/netmsg.h
---- ninjam-cclient-0.01a/ninjam/netmsg.h 2005-08-30 03:16:06.000000000 +0000
-+++ ninjam/ninjam/netmsg.h 1970-01-01 00:00:00.000000000 +0000
-@@ -1,129 +0,0 @@
--/*
-- NINJAM - netmsg.h
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This header provides the declarations for the Net_Messsage class, and
-- Net_Connection class (handles sending and receiving Net_Messages to
-- a JNetLib JNL_Connection).
--*/
--
--
--
--#ifndef _NETMSG_H_
--#define _NETMSG_H_
--
--#include "../WDL/queue.h"
--#include "../WDL/jnetlib/jnetlib.h"
--
--#define NET_MESSAGE_MAX_SIZE 16384
--
--#define NET_CON_MAX_MESSAGES 512
--
--#define MESSAGE_KEEPALIVE 0xfd
--#define MESSAGE_EXTENDED 0xfe
--#define MESSAGE_INVALID 0xff
--
--#define NET_CON_KEEPALIVE_RATE 3
--
--
--class Net_Message
--{
-- public:
-- Net_Message() : m_parsepos(0), m_refcnt(0), m_type(MESSAGE_INVALID)
-- {
-- }
-- ~Net_Message()
-- {
-- }
--
--
-- void set_type(int type) { m_type=type; }
-- int get_type() { return m_type; }
--
-- void set_size(int newsize) { m_hb.Resize(newsize); }
-- int get_size() { return m_hb.GetSize(); }
--
-- void *get_data() { return m_hb.Get(); }
--
--
-- int parseMessageHeader(void *data, int len); // returns bytes used, if any (or 0 if more data needed), or -1 if invalid
-- int parseBytesNeeded();
-- int parseAddBytes(void *data, int len); // returns bytes actually added
--
-- int makeMessageHeader(void *data); // makes message header, returns length. data should be at least 16 bytes to be safe
--
--
-- void addRef() { ++m_refcnt; }
-- void releaseRef() { if (--m_refcnt < 1) delete this; }
--
-- private:
-- int m_parsepos;
-- int m_refcnt;
-- int m_type;
-- WDL_HeapBuf m_hb;
--};
--
--
--class Net_Connection
--{
-- public:
-- Net_Connection() : m_error(0),m_msgsendpos(-1), m_recvstate(0),m_recvmsg(0),m_con(0)
-- {
-- SetKeepAlive(0);
-- }
-- ~Net_Connection();
--
-- void attach(JNL_Connection *con)
-- {
-- m_con=con;
-- }
--
-- Net_Message *Run(int *wantsleep=0);
-- int Send(Net_Message *msg); // -1 on error, i.e. queue full
-- int GetStatus(); // returns <0 on error, 0 on normal, 1 on disconnect
-- JNL_Connection *GetConnection() { return m_con; }
--
-- void SetKeepAlive(int interval)
-- {
-- m_keepalive=interval?interval:NET_CON_KEEPALIVE_RATE;
-- m_last_send=m_last_recv=time(NULL);
-- }
--
-- void Kill(int quick=0);
--
-- private:
-- int m_error;
--
-- int m_keepalive;
-- int m_msgsendpos;
--
-- time_t m_last_send, m_last_recv;
--
-- int m_recvstate;
-- Net_Message *m_recvmsg;
--
-- JNL_Connection *m_con;
-- WDL_Queue m_sendq;
--
--
--};
--
--
--#endif
-diff -Naur ninjam-cclient-0.01a/ninjam/njclient.cpp ninjam/ninjam/njclient.cpp
---- ninjam-cclient-0.01a/ninjam/njclient.cpp 2005-08-30 03:16:06.000000000 +0000
-+++ ninjam/ninjam/njclient.cpp 1970-01-01 00:00:00.000000000 +0000
-@@ -1,2142 +0,0 @@
--/*
-- NINJAM - njclient.cpp
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- For a full description of everything here, see njclient.h
--*/
--
--
--#include <math.h>
--#include <stdio.h>
--#include <stdarg.h>
--#include "njclient.h"
--#include "mpb.h"
--#include "../WDL/pcmfmtcvt.h"
--#include "../WDL/wavwrite.h"
--
--
--
--// todo: make an interface base class for vorbis enc/dec
--#define VorbisEncoder I_NJEncoder
--#define VorbisDecoder I_NJDecoder
--#define NJ_ENCODER_FMT_TYPE MAKE_NJ_FOURCC('O','G','G','v')
--#include "../WDL/vorbisencdec.h"
--#undef VorbisEncoder
--#undef VorbisDecoder
--
--
--#define MAKE_NJ_FOURCC(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24))
--
--class DecodeState
--{
-- public:
-- DecodeState() : decode_fp(0), decode_codec(0), dump_samples(0),
-- decode_samplesout(0), resample_state(0.0), decode_peak_vol(0.0)
-- {
-- memset(guid,0,sizeof(guid));
-- }
-- ~DecodeState()
-- {
-- delete decode_codec;
-- decode_codec=0;
-- if (decode_fp) fclose(decode_fp);
-- decode_fp=0;
--
-- if (delete_on_delete.Get()[0])
-- {
--#ifdef _WIN32
-- DeleteFile(delete_on_delete.Get());
--#else
-- unlink(delete_on_delete.Get());
--#endif
-- }
-- }
--
-- unsigned char guid[16];
-- double decode_peak_vol;
--
-- WDL_String delete_on_delete;
--
-- FILE *decode_fp;
-- I_NJDecoder *decode_codec;
-- int decode_samplesout;
-- int dump_samples;
-- double resample_state;
--
--};
--
--
--class RemoteUser_Channel
--{
-- public:
-- RemoteUser_Channel();
-- ~RemoteUser_Channel();
--
-- float volume, pan;
--
-- WDL_String name;
--
-- // decode/mixer state, used by mixer
-- DecodeState *ds;
-- DecodeState *next_ds[2]; // prepared by main thread, for audio thread
--
--};
--
--class RemoteUser
--{
--public:
-- RemoteUser() : muted(0), volume(1.0f), pan(0.0f), submask(0), mutedmask(0), solomask(0), chanpresentmask(0) { }
-- ~RemoteUser() { }
--
-- bool muted;
-- float volume;
-- float pan;
-- WDL_String name;
-- int submask;
-- int chanpresentmask;
-- int mutedmask;
-- int solomask;
-- RemoteUser_Channel channels[MAX_USER_CHANNELS];
--};
--
--
--class RemoteDownload
--{
--public:
-- RemoteDownload();
-- ~RemoteDownload();
--
-- void Close();
-- void Open(NJClient *parent, unsigned int fourcc);
-- void Write(void *buf, int len);
-- void startPlaying(int force=0); // call this with 1 to make sure it gets played ASAP, or let RemoteDownload call it automatically
--
-- time_t last_time;
-- unsigned char guid[16];
--
-- int chidx;
-- WDL_String username;
-- int playtime;
--
--private:
-- unsigned int m_fourcc;
-- NJClient *m_parent;
-- FILE *fp;
--};
--
--
--
--class BufferQueue
--{
-- public:
-- BufferQueue() { }
-- ~BufferQueue()
-- {
-- Clear();
-- }
--
-- void AddBlock(float *samples, int len, float *samples2=NULL);
-- int GetBlock(WDL_HeapBuf **b); // return 0 if got one, 1 if none avail
-- void DisposeBlock(WDL_HeapBuf *b);
--
-- void Clear()
-- {
-- int x;
-- for (x = 0; x < m_emptybufs.GetSize(); x ++)
-- delete m_emptybufs.Get(x);
-- m_emptybufs.Empty();
-- int l=m_samplequeue.Available()/4;
-- WDL_HeapBuf **bufs=(WDL_HeapBuf **)m_samplequeue.Get();
-- if (bufs) while (l--)
-- {
-- if ((int)*bufs != 0 && (int)*bufs != -1) delete *bufs;
-- bufs++;
-- }
-- m_samplequeue.Advance(m_samplequeue.Available());
-- m_samplequeue.Compact();
-- }
--
-- private:
-- WDL_Queue m_samplequeue; // a list of pointers, with NULL to define spaces
-- WDL_PtrList<WDL_HeapBuf> m_emptybufs;
-- WDL_Mutex m_cs;
--};
--
--
--class Local_Channel
--{
--public:
-- Local_Channel();
-- ~Local_Channel();
--
-- int channel_idx;
--
-- int src_channel; // 0 or 1
-- int bitrate;
--
-- float volume;
-- float pan;
-- bool muted;
-- bool solo;
--
-- //?
-- // mode flag. 0=silence, 1=broadcasting
-- bool broadcasting; //takes effect next loop
--
--
--
-- // internal state. should ONLY be used by the audio thread.
-- bool bcast_active;
--
--
-- void (*cbf)(float *, int ns, void *);
-- void *cbf_inst;
--
-- BufferQueue m_bq;
--
-- double decode_peak_vol;
-- bool m_need_header;
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- I_NJEncoder *m_enc;
-- int m_enc_bitrate_used;
-- Net_Message *m_enc_header_needsend;
--#endif
--
-- WDL_String name;
-- RemoteDownload m_curwritefile;
-- WaveWriter *m_wavewritefile;
--
-- //DecodeState too, eventually
--};
--
--
--
--
--
--
--
--#define MIN_ENC_BLOCKSIZE 2048
--#define MAX_ENC_BLOCKSIZE (8192+1024)
--
--
--#define NJ_PORT 2049
--
--static unsigned char zero_guid[16];
--
--
--static void guidtostr(unsigned char *guid, char *str)
--{
-- int x;
-- for (x = 0; x < 16; x ++) wsprintf(str+x*2,"%02x",guid[x]);
--}
--static char *guidtostr_tmp(unsigned char *guid)
--{
-- static char tmp[64];
-- guidtostr(guid,tmp);
-- return tmp;
--}
--
--
--static int is_type_char_valid(int c)
--{
-- c&=0xff;
-- return (c >= 'a' && c <= 'z') ||
-- (c >= 'A' && c <= 'Z') ||
-- (c >= '0' && c <= '9') ||
-- c == ' ' || c == '-' ||
-- c == '.' || c == '_';
--}
--
--static int is_type_valid(unsigned int t)
--{
-- return (t&0xff) != ' ' &&
-- is_type_char_valid(t>>24) &&
-- is_type_char_valid(t>>16) &&
-- is_type_char_valid(t>>8) &&
-- is_type_char_valid(t);
--}
--
--
--static void type_to_string(unsigned int t, char *out)
--{
-- if (is_type_valid(t))
-- {
-- out[0]=(t)&0xff;
-- out[1]=(t>>8)&0xff;
-- out[2]=(t>>16)&0xff;
-- out[3]=' ';//(t>>24)&0xff;
-- out[4]=0;
-- int x=3;
-- while (out[x]==' ' && x > 0) out[x--]=0;
-- }
-- else *out=0;
--}
--
--static unsigned int string_to_type(char *in)
--{
-- int n;
-- unsigned int ret=*in;
-- if (*in == ' ' || !is_type_char_valid(*in)) return 0;
-- in++;
-- for (n = 0; n < 3; n ++)
-- {
-- if (!is_type_char_valid(*in)) break;
-- ret|=(*in<<(8+8*n));
-- in++;
-- }
-- if (*in) return 0;
-- return ret;
--}
--
--
--void NJClient::makeFilenameFromGuid(WDL_String *s, unsigned char *guid)
--{
-- char buf[256];
-- guidtostr(guid,buf);
--
-- s->Set(m_workdir.Get());
--#ifdef _WIN32
-- char tmp[3]={buf[0],'\\',0};
--#else
-- char tmp[3]={buf[0],'/',0};
--#endif
-- s->Append(tmp);
-- s->Append(buf);
--}
--
--
--
--
--NJClient::NJClient()
--{
-- m_wavebq=new BufferQueue;
-- m_userinfochange=0;
-- m_loopcnt=0;
-- m_srate=48000;
--#ifdef _WIN32
-- DWORD v=GetTickCount();
-- WDL_RNG_addentropy(&v,sizeof(v));
-- v=(DWORD)time(NULL);
-- WDL_RNG_addentropy(&v,sizeof(v));
--#else
-- time_t v=time(NULL);
-- WDL_RNG_addentropy(&v,sizeof(v));
--#endif
--
-- config_autosubscribe=1;
-- config_savelocalaudio=0;
-- config_metronome=0.5f;
-- config_metronome_pan=0.0f;
-- config_metronome_mute=false;
-- config_debug_level=0;
-- config_mastervolume=1.0f;
-- config_masterpan=0.0f;
-- config_mastermute=false;
-- config_play_prebuffer=8192;
--
--
-- LicenseAgreement_User32=0;
-- LicenseAgreementCallback=0;
-- ChatMessage_Callback=0;
-- ChatMessage_User32=0;
-- ChannelMixer=0;
-- ChannelMixer_User32=0;
--
-- waveWrite=0;
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- m_oggWrite=0;
-- m_oggComp=0;
--#endif
-- m_logFile=0;
--
-- m_issoloactive=0;
-- m_netcon=0;
--
-- _reinit();
--
-- m_session_pos_ms=m_session_pos_samples=0;
--}
--
--void NJClient::_reinit()
--{
-- m_max_localch=MAX_LOCAL_CHANNELS;
-- output_peaklevel=0.0;
--
-- m_connection_keepalive=0;
-- m_status=-1;
--
-- m_in_auth=0;
--
-- m_bpm=120;
-- m_bpi=32;
--
-- m_beatinfo_updated=1;
--
-- m_audio_enable=0;
--
-- m_active_bpm=120;
-- m_active_bpi=32;
-- m_interval_length=1000;
-- m_interval_pos=-1;
-- m_metronome_pos=0.0;
-- m_metronome_state=0;
-- m_metronome_tmp=0;
-- m_metronome_interval=0;
--
-- m_issoloactive&=~1;
--
-- int x;
-- for (x = 0; x < m_locchannels.GetSize(); x ++)
-- m_locchannels.Get(x)->decode_peak_vol=0.0f;
--
--}
--
--
--void NJClient::writeLog(char *fmt, ...)
--{
-- if (m_logFile)
-- {
-- va_list ap;
-- va_start(ap,fmt);
--
-- m_log_cs.Enter();
-- if (m_logFile) vfprintf(m_logFile,fmt,ap);
-- m_log_cs.Leave();
--
-- va_end(ap);
--
-- }
--
--
--}
--
--void NJClient::SetLogFile(char *name)
--{
-- m_log_cs.Enter();
-- if (m_logFile) fclose(m_logFile);
-- m_logFile=0;
-- if (name && *name)
-- {
-- if (!strstr(name,"\\") && !strstr(name,"/") && !strstr(name,":"))
-- {
-- WDL_String s(m_workdir.Get());
-- s.Append(name);
-- m_logFile=fopen(s.Get(),"a+t");
-- }
-- else
-- m_logFile=fopen(name,"a+t");
-- }
-- m_log_cs.Leave();
--}
--
--
--NJClient::~NJClient()
--{
-- delete m_netcon;
-- m_netcon=0;
--
-- delete waveWrite;
-- SetOggOutFile(NULL,0,0);
--
-- if (m_logFile)
-- {
-- writeLog("end\n");
-- fclose(m_logFile);
-- m_logFile=0;
-- }
--
-- int x;
-- for (x = 0; x < m_remoteusers.GetSize(); x ++) delete m_remoteusers.Get(x);
-- m_remoteusers.Empty();
-- for (x = 0; x < m_downloads.GetSize(); x ++) delete m_downloads.Get(x);
-- m_downloads.Empty();
-- for (x = 0; x < m_locchannels.GetSize(); x ++) delete m_locchannels.Get(x);
-- m_locchannels.Empty();
--
-- delete m_wavebq;
--}
--
--
--void NJClient::updateBPMinfo(int bpm, int bpi)
--{
-- m_misc_cs.Enter();
-- m_bpm=bpm;
-- m_bpi=bpi;
-- m_beatinfo_updated=1;
-- m_misc_cs.Leave();
--}
--
--
--void NJClient::GetPosition(int *pos, int *length) // positions in samples
--{
-- if (length) *length=m_interval_length;
-- if (pos && (*pos=m_interval_pos)<0) *pos=0;
--}
--
--unsigned int NJClient::GetSessionPosition()// returns milliseconds
--{
-- unsigned int a=m_session_pos_ms;
-- if (m_srate)
-- a+=(m_session_pos_samples*1000)/m_srate;
-- return a;
--}
--
--void NJClient::AudioProc(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate)
--{
-- m_srate=srate;
-- // zero output
-- int x;
-- for (x = 0; x < outnch; x ++) memset(outbuf[x],0,sizeof(float)*len);
--
-- if (!m_audio_enable)
-- {
-- process_samples(inbuf,innch,outbuf,outnch,len,srate,0,1);
-- return;
-- }
--
-- if (srate>0)
-- {
-- unsigned int spl=m_session_pos_samples;
-- unsigned int sec=m_session_pos_ms;
--
-- spl += len;
-- if (spl >= (unsigned int)srate)
-- {
-- sec += (spl/srate)*1000;
-- spl %= srate;
-- }
-- // writing these both like this reduces the chance that the
-- // main thread will read them and get a mix. still possible, tho,
-- // but super unlikely
-- m_session_pos_samples=spl;
-- m_session_pos_ms=sec;
-- }
--
--
--
-- int offs=0;
--
-- while (len > 0)
-- {
-- int x=m_interval_length-m_interval_pos;
-- if (!x || m_interval_pos < 0)
-- {
-- m_misc_cs.Enter();
-- if (m_beatinfo_updated)
-- {
-- double v=(double)m_bpm*(1.0/60.0);
-- // beats per second
--
-- // (beats/interval) / (beats/sec)
-- v = (double) m_bpi / v;
--
-- // seconds/interval
--
-- // samples/interval
-- v *= (double) srate;
--
-- m_beatinfo_updated=0;
-- m_interval_length = (int)v;
-- //m_interval_length-=m_interval_length%1152;//hack
-- m_active_bpm=m_bpm;
-- m_active_bpi=m_bpi;
-- m_metronome_interval=(int) ((double)m_interval_length / (double)m_active_bpi);
-- }
-- m_misc_cs.Leave();
--
-- // new buffer time
-- on_new_interval();
--
-- m_interval_pos=0;
-- x=m_interval_length;
-- }
--
-- if (x > len) x=len;
--
-- process_samples(inbuf,innch,outbuf,outnch,x,srate,offs);
--
-- m_interval_pos+=x;
-- offs += x;
-- len -= x;
-- }
--
--}
--
--
--void NJClient::Disconnect()
--{
-- m_errstr.Set("");
-- m_host.Set("");
-- m_user.Set("");
-- m_pass.Set("");
-- delete m_netcon;
-- m_netcon=0;
--
-- int x;
-- for (x=0;x<m_remoteusers.GetSize(); x++) delete m_remoteusers.Get(x);
-- m_remoteusers.Empty();
-- if (x) m_userinfochange=1; // if we removed users, notify parent
--
-- for (x = 0; x < m_downloads.GetSize(); x ++) delete m_downloads.Get(x);
--
--
-- for (x = 0; x < m_locchannels.GetSize(); x ++)
-- {
-- Local_Channel *c=m_locchannels.Get(x);
-- delete c->m_wavewritefile;
-- c->m_wavewritefile=0;
-- c->m_curwritefile.Close();
--
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- delete c->m_enc;
-- c->m_enc=0;
-- delete c->m_enc_header_needsend;
-- c->m_enc_header_needsend=0;
--#endif
--
-- c->m_bq.Clear();
-- }
-- m_downloads.Empty();
--
-- m_wavebq->Clear();
--
-- _reinit();
--}
--
--void NJClient::Connect(char *host, char *user, char *pass)
--{
-- Disconnect();
--
-- m_session_pos_ms=m_session_pos_samples=0;
--
-- m_host.Set(host);
-- m_user.Set(user);
-- m_pass.Set(pass);
--
-- WDL_String tmp(m_host.Get());
-- int port=NJ_PORT;
-- char *p=strstr(tmp.Get(),":");
-- if (p)
-- {
-- *p=0;
-- port=atoi(++p);
-- if (!port) port=NJ_PORT;
-- }
-- JNL_Connection *c=new JNL_Connection(JNL_CONNECTION_AUTODNS,65536,65536);
-- c->connect(tmp.Get(),port);
-- m_netcon = new Net_Connection;
-- m_netcon->attach(c);
--
-- m_status=0;
--}
--
--int NJClient::GetStatus()
--{
-- if (!m_status || m_status == -1) return NJC_STATUS_PRECONNECT;
-- if (m_status == 1000) return NJC_STATUS_CANTCONNECT;
-- if (m_status == 1001) return NJC_STATUS_INVALIDAUTH;
-- if (m_status == 1002) return NJC_STATUS_DISCONNECTED;
--
-- return NJC_STATUS_OK;
--}
--
--
--int NJClient::Run() // nonzero if sleep ok
--{
-- WDL_HeapBuf *p=0;
-- while (!m_wavebq->GetBlock(&p))
-- {
-- if (p)
-- {
-- float *f=(float*)p->Get();
-- int hl=p->GetSize()/(2*sizeof(float));
-- float *outbuf[2]={f,f+hl};
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- if (m_oggWrite&&m_oggComp)
-- {
-- m_oggComp->Encode(f,hl,1,hl);
-- if (m_oggComp->outqueue.Available())
-- {
-- fwrite((char *)m_oggComp->outqueue.Get(),1,m_oggComp->outqueue.Available(),m_oggWrite);
-- m_oggComp->outqueue.Advance(m_oggComp->outqueue.Available());
-- m_oggComp->outqueue.Compact();
-- }
-- }
--#endif
-- if (waveWrite)
-- {
-- waveWrite->WriteFloatsNI(outbuf,0,hl);
-- }
-- m_wavebq->DisposeBlock(p);
-- }
-- }
--//
-- int wantsleep=1;
--
-- if (m_netcon)
-- {
-- Net_Message *msg=m_netcon->Run(&wantsleep);
-- if (!msg)
-- {
-- if (m_netcon->GetStatus())
-- {
-- m_audio_enable=0;
-- if (m_in_auth) m_status=1001;
-- if (m_status > 0 && m_status < 1000) m_status=1002;
-- if (m_status == 0) m_status=1000;
-- return 1;
-- }
-- }
-- else
-- {
-- msg->addRef();
--
-- switch (msg->get_type())
-- {
-- case MESSAGE_SERVER_AUTH_CHALLENGE:
-- {
-- mpb_server_auth_challenge cha;
-- if (!cha.parse(msg))
-- {
-- if (cha.protocol_version < PROTO_VER_MIN || cha.protocol_version >= PROTO_VER_MAX)
-- {
-- m_errstr.Set("server is incorrect protocol version");
-- m_status = 1001;
-- m_netcon->Kill();
-- return 0;
-- }
--
-- mpb_client_auth_user repl;
-- repl.username=m_user.Get();
-- repl.client_version=PROTO_VER_CUR; // client version number
--
-- m_connection_keepalive=(cha.server_caps>>8)&0xff;
--
--// printf("Got keepalive of %d\n",m_connection_keepalive);
--
-- if (cha.license_agreement)
-- {
-- m_netcon->SetKeepAlive(45);
-- if (LicenseAgreementCallback && LicenseAgreementCallback(LicenseAgreement_User32,cha.license_agreement))
-- {
-- repl.client_caps|=1;
-- }
-- }
-- m_netcon->SetKeepAlive(m_connection_keepalive);
--
-- WDL_SHA1 tmp;
-- tmp.add(m_user.Get(),strlen(m_user.Get()));
-- tmp.add(":",1);
-- tmp.add(m_pass.Get(),strlen(m_pass.Get()));
-- tmp.result(repl.passhash);
--
-- tmp.reset(); // new auth method is SHA1(SHA1(user:pass)+challenge)
-- tmp.add(repl.passhash,sizeof(repl.passhash));
-- tmp.add(cha.challenge,sizeof(cha.challenge));
-- tmp.result(repl.passhash);
--
-- m_netcon->Send(repl.build());
--
-- m_in_auth=1;
-- }
-- }
-- break;
-- case MESSAGE_SERVER_AUTH_REPLY:
-- {
-- mpb_server_auth_reply ar;
-- if (!ar.parse(msg))
-- {
-- if (ar.flag) // send our channel information
-- {
-- mpb_client_set_channel_info sci;
-- int x;
-- for (x = 0; x < m_locchannels.GetSize(); x ++)
-- {
-- Local_Channel *ch=m_locchannels.Get(x);
-- sci.build_add_rec(ch->name.Get(),0,0,0);
-- }
-- m_netcon->Send(sci.build());
-- m_status=2;
-- m_in_auth=0;
-- m_max_localch=ar.maxchan;
-- if (ar.errmsg)
-- m_user.Set(ar.errmsg); // server gave us an updated name
-- }
-- else
-- {
-- if (ar.errmsg)
-- {
-- m_errstr.Set(ar.errmsg);
-- }
-- m_status = 1001;
-- m_netcon->Kill();
-- }
-- }
-- }
-- break;
-- case MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY:
-- {
-- mpb_server_config_change_notify ccn;
-- if (!ccn.parse(msg))
-- {
-- updateBPMinfo(ccn.beats_minute,ccn.beats_interval);
-- m_audio_enable=1;
-- }
-- }
--
-- break;
-- case MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY:
-- {
-- mpb_server_userinfo_change_notify ucn;
-- if (!ucn.parse(msg))
-- {
-- int offs=0;
-- int a=0, cid=0, p=0,f=0;
-- short v=0;
-- char *un=0,*chn=0;
-- while ((offs=ucn.parse_get_rec(offs,&a,&cid,&v,&p,&f,&un,&chn))>0)
-- {
-- if (!un) un="";
-- if (!chn) chn="";
--
-- m_userinfochange=1;
--
-- int x;
-- // todo: per-user autosubscribe option, or callback
-- // todo: have volume/pan settings here go into defaults for the channel. or not, kinda think it's pointless
-- if (cid >= 0 && cid < MAX_USER_CHANNELS)
-- {
-- RemoteUser *theuser;
-- for (x = 0; x < m_remoteusers.GetSize() && strcmp((theuser=m_remoteusers.Get(x))->name.Get(),un); x ++);
--
-- // printf("user %s, channel %d \"%s\": %s v:%d.%ddB p:%d flag=%d\n",un,cid,chn,a?"active":"inactive",(int)v/10,abs((int)v)%10,p,f);
--
--
-- m_users_cs.Enter();
-- if (a)
-- {
-- if (x == m_remoteusers.GetSize())
-- {
-- theuser=new RemoteUser;
-- theuser->name.Set(un);
-- m_remoteusers.Add(theuser);
-- }
--
-- theuser->channels[cid].name.Set(chn);
-- theuser->chanpresentmask |= 1<<cid;
--
--
-- if (config_autosubscribe)
-- {
-- theuser->submask |= 1<<cid;
-- mpb_client_set_usermask su;
-- su.build_add_rec(un,theuser->submask);
-- m_netcon->Send(su.build());
-- }
-- }
-- else
-- {
-- if (x < m_remoteusers.GetSize())
-- {
-- theuser->channels[cid].name.Set("");
-- theuser->chanpresentmask &= ~(1<<cid);
-- theuser->submask &= ~(1<<cid);
--
-- int chksolo=theuser->solomask == (1<<cid);
-- theuser->solomask &= ~(1<<cid);
--
-- delete theuser->channels[cid].ds;
-- delete theuser->channels[cid].next_ds[0];
-- delete theuser->channels[cid].next_ds[1];
-- theuser->channels[cid].ds=0;
-- theuser->channels[cid].next_ds[0]=0;
-- theuser->channels[cid].next_ds[1]=0;
--
-- if (!theuser->chanpresentmask) // user no longer exists, it seems
-- {
-- chksolo=1;
-- delete theuser;
-- m_remoteusers.Delete(x);
-- }
--
-- if (chksolo)
-- {
-- int i;
-- for (i = 0; i < m_remoteusers.GetSize() && !m_remoteusers.Get(i)->solomask; i ++);
--
-- if (i < m_remoteusers.GetSize()) m_issoloactive|=1;
-- else m_issoloactive&=~1;
-- }
-- }
-- }
-- m_users_cs.Leave();
-- }
-- }
-- }
-- }
-- break;
-- case MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN:
-- {
-- mpb_server_download_interval_begin dib;
-- if (!dib.parse(msg) && dib.username)
-- {
-- int x;
-- RemoteUser *theuser;
-- for (x = 0; x < m_remoteusers.GetSize() && strcmp((theuser=m_remoteusers.Get(x))->name.Get(),dib.username); x ++);
-- if (x < m_remoteusers.GetSize() && dib.chidx >= 0 && dib.chidx < MAX_USER_CHANNELS)
-- {
-- //printf("Getting interval for %s, channel %d\n",dib.username,dib.chidx);
-- if (!memcmp(dib.guid,zero_guid,sizeof(zero_guid)))
-- {
-- m_users_cs.Enter();
-- int useidx=!!theuser->channels[dib.chidx].next_ds[0];
-- DecodeState *tmp=theuser->channels[dib.chidx].next_ds[useidx];
-- theuser->channels[dib.chidx].next_ds[useidx]=0;
-- m_users_cs.Leave();
-- delete tmp;
-- }
-- else if (dib.fourcc) // download coming
-- {
-- if (config_debug_level>1) printf("RECV BLOCK %s\n",guidtostr_tmp(dib.guid));
-- RemoteDownload *ds=new RemoteDownload;
-- memcpy(ds->guid,dib.guid,sizeof(ds->guid));
-- ds->Open(this,dib.fourcc);
--
-- ds->playtime=config_play_prebuffer;
-- ds->chidx=dib.chidx;
-- ds->username.Set(dib.username);
--
-- m_downloads.Add(ds);
-- }
-- else
-- {
-- DecodeState *tmp=start_decode(dib.guid);
-- m_users_cs.Enter();
-- int useidx=!!theuser->channels[dib.chidx].next_ds[0];
-- DecodeState *t2=theuser->channels[dib.chidx].next_ds[useidx];
-- theuser->channels[dib.chidx].next_ds[useidx]=tmp;
-- m_users_cs.Leave();
-- delete t2;
-- }
--
-- }
-- }
-- }
-- break;
-- case MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE:
-- {
-- mpb_server_download_interval_write diw;
-- if (!diw.parse(msg))
-- {
-- time_t now;
-- time(&now);
-- int x;
-- for (x = 0; x < m_downloads.GetSize(); x ++)
-- {
-- RemoteDownload *ds=m_downloads.Get(x);
-- if (ds)
-- {
-- if (!memcmp(ds->guid,diw.guid,sizeof(ds->guid)))
-- {
-- if (config_debug_level>1) printf("RECV BLOCK DATA %s%s %d bytes\n",guidtostr_tmp(diw.guid),diw.flags&1?":end":"",diw.audio_data_len);
--
-- ds->last_time=now;
-- if (diw.audio_data_len > 0 && diw.audio_data)
-- {
-- ds->Write(diw.audio_data,diw.audio_data_len);
-- }
-- if (diw.flags & 1)
-- {
-- delete ds;
-- m_downloads.Delete(x);
-- }
-- break;
-- }
--
-- if (now - ds->last_time > DOWNLOAD_TIMEOUT)
-- {
-- ds->chidx=-1;
-- delete ds;
-- m_downloads.Delete(x--);
-- }
-- }
-- }
-- }
-- }
-- break;
-- case MESSAGE_CHAT_MESSAGE:
-- if (ChatMessage_Callback)
-- {
-- mpb_chat_message foo;
-- if (!foo.parse(msg))
-- {
-- ChatMessage_Callback(ChatMessage_User32,this,foo.parms,sizeof(foo.parms)/sizeof(foo.parms[0]));
-- }
-- }
-- break;
-- default:
-- //printf("Got unknown message %02X\n",msg->get_type());
-- break;
-- }
--
-- msg->releaseRef();
-- }
-- }
--
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- int u;
-- for (u = 0; u < m_locchannels.GetSize(); u ++)
-- {
-- Local_Channel *lc=m_locchannels.Get(u);
-- WDL_HeapBuf *p=0;
-- while (!lc->m_bq.GetBlock(&p))
-- {
-- wantsleep=0;
-- if (u >= m_max_localch)
-- {
-- if (p && (int)p != -1)
-- lc->m_bq.DisposeBlock(p);
-- p=0;
-- continue;
-- }
--
-- if ((int)p == -1)
-- {
-- mpb_client_upload_interval_begin cuib;
-- cuib.chidx=lc->channel_idx;
-- memset(cuib.guid,0,sizeof(cuib.guid));
-- memset(lc->m_curwritefile.guid,0,sizeof(lc->m_curwritefile.guid));
-- cuib.fourcc=0;
-- cuib.estsize=0;
-- m_netcon->Send(cuib.build());
-- p=0;
-- }
-- else if (p)
-- {
-- // encode data
-- if (!lc->m_enc)
-- {
-- lc->m_enc = new I_NJEncoder(m_srate,1,lc->m_enc_bitrate_used = lc->bitrate,WDL_RNG_int32());
-- }
--
-- if (lc->m_need_header)
-- {
-- lc->m_need_header=false;
-- {
-- WDL_RNG_bytes(lc->m_curwritefile.guid,sizeof(lc->m_curwritefile.guid));
-- char guidstr[64];
-- guidtostr(lc->m_curwritefile.guid,guidstr);
-- writeLog("local %s %d\n",guidstr,lc->channel_idx);
-- if (config_savelocalaudio>0)
-- {
-- lc->m_curwritefile.Open(this,NJ_ENCODER_FMT_TYPE);
-- if (lc->m_wavewritefile) delete lc->m_wavewritefile;
-- lc->m_wavewritefile=0;
-- if (config_savelocalaudio>1)
-- {
-- WDL_String fn;
--
-- fn.Set(m_workdir.Get());
-- #ifdef _WIN32
-- char tmp[3]={guidstr[0],'\\',0};
-- #else
-- char tmp[3]={guidstr[0],'/',0};
-- #endif
-- fn.Append(tmp);
-- fn.Append(guidstr);
-- fn.Append(".wav");
--
-- lc->m_wavewritefile=new WaveWriter(fn.Get(),24,1,m_srate);
-- }
-- }
--
-- mpb_client_upload_interval_begin cuib;
-- cuib.chidx=lc->channel_idx;
-- memcpy(cuib.guid,lc->m_curwritefile.guid,sizeof(cuib.guid));
-- cuib.fourcc=NJ_ENCODER_FMT_TYPE;
-- cuib.estsize=0;
-- delete lc->m_enc_header_needsend;
-- lc->m_enc_header_needsend=cuib.build();
-- }
-- }
--
-- if (lc->m_enc)
-- {
-- if (lc->m_wavewritefile)
-- {
-- lc->m_wavewritefile->WriteFloats((float*)p->Get(),p->GetSize()/sizeof(float));
-- }
-- lc->m_enc->Encode((float*)p->Get(),p->GetSize()/sizeof(float));
--
-- int s;
-- while ((s=lc->m_enc->outqueue.Available())>(lc->m_enc_header_needsend?MIN_ENC_BLOCKSIZE*4:MIN_ENC_BLOCKSIZE))
-- {
-- if (s > MAX_ENC_BLOCKSIZE) s=MAX_ENC_BLOCKSIZE;
--
-- {
-- mpb_client_upload_interval_write wh;
-- memcpy(wh.guid,lc->m_curwritefile.guid,sizeof(lc->m_curwritefile.guid));
-- wh.flags=0;
-- wh.audio_data=lc->m_enc->outqueue.Get();
-- wh.audio_data_len=s;
-- lc->m_curwritefile.Write(wh.audio_data,wh.audio_data_len);
--
-- if (lc->m_enc_header_needsend)
-- {
-- if (config_debug_level>1)
-- {
-- mpb_client_upload_interval_begin dib;
-- dib.parse(lc->m_enc_header_needsend);
-- printf("SEND BLOCK HEADER %s\n",guidtostr_tmp(dib.guid));
-- }
-- m_netcon->Send(lc->m_enc_header_needsend);
-- lc->m_enc_header_needsend=0;
-- }
--
-- if (config_debug_level>1) printf("SEND BLOCK %s%s %d bytes\n",guidtostr_tmp(wh.guid),wh.flags&1?"end":"",wh.audio_data_len);
--
-- m_netcon->Send(wh.build());
-- }
--
-- lc->m_enc->outqueue.Advance(s);
-- }
-- lc->m_enc->outqueue.Compact();
-- }
-- lc->m_bq.DisposeBlock(p);
-- p=0;
-- }
-- else
-- {
-- if (lc->m_enc)
-- {
-- // finish any encoding
-- lc->m_enc->Encode(NULL,0);
--
-- // send any final message, with the last one with a flag
-- // saying "we're done"
-- do
-- {
-- mpb_client_upload_interval_write wh;
-- int l=lc->m_enc->outqueue.Available();
-- if (l>MAX_ENC_BLOCKSIZE) l=MAX_ENC_BLOCKSIZE;
--
-- memcpy(wh.guid,lc->m_curwritefile.guid,sizeof(wh.guid));
-- wh.audio_data=lc->m_enc->outqueue.Get();
-- wh.audio_data_len=l;
--
-- lc->m_curwritefile.Write(wh.audio_data,wh.audio_data_len);
--
-- lc->m_enc->outqueue.Advance(l);
-- wh.flags=lc->m_enc->outqueue.GetSize()>0 ? 0 : 1;
--
-- if (lc->m_enc_header_needsend)
-- {
-- if (config_debug_level>1)
-- {
-- mpb_client_upload_interval_begin dib;
-- dib.parse(lc->m_enc_header_needsend);
-- printf("SEND BLOCK HEADER %s\n",guidtostr_tmp(dib.guid));
-- }
-- m_netcon->Send(lc->m_enc_header_needsend);
-- lc->m_enc_header_needsend=0;
-- }
--
-- if (config_debug_level>1) printf("SEND BLOCK %s%s %d bytes\n",guidtostr_tmp(wh.guid),wh.flags&1?"end":"",wh.audio_data_len);
-- m_netcon->Send(wh.build());
-- }
-- while (lc->m_enc->outqueue.Available()>0);
-- lc->m_enc->outqueue.Compact(); // free any memory left
--
-- //delete m_enc;
-- // m_enc=0;
-- lc->m_enc->reinit();
-- }
--
-- if (lc->m_enc && lc->bitrate != lc->m_enc_bitrate_used)
-- {
-- delete lc->m_enc;
-- lc->m_enc=0;
-- }
-- lc->m_need_header=true;
--
-- // end the last encode
-- }
-- }
-- }
--#endif
--
-- return wantsleep;
--
--}
--
--
--DecodeState *NJClient::start_decode(unsigned char *guid, unsigned int fourcc)
--{
-- DecodeState *newstate=new DecodeState;
-- memcpy(newstate->guid,guid,sizeof(newstate->guid));
--
-- WDL_String s;
--
-- makeFilenameFromGuid(&s,guid);
--
-- // todo: make plug-in system to allow encoders to add types allowed
-- // todo: with a preference for 'fourcc' if specified
-- unsigned int types[]={MAKE_NJ_FOURCC('O','G','G','v')}; // only types we understand
--
-- int oldl=strlen(s.Get())+1;
-- s.Append(".XXXXXXXXX");
-- unsigned int x;
-- for (x = 0; !newstate->decode_fp && x < sizeof(types)/sizeof(types[0]); x ++)
-- {
-- type_to_string(types[x],s.Get()+oldl);
-- newstate->decode_fp=fopen(s.Get(),"rb");
-- }
--
-- if (newstate->decode_fp)
-- {
-- if (config_savelocalaudio<0)
-- {
-- newstate->delete_on_delete.Set(s.Get());
-- }
-- newstate->decode_codec= new I_NJDecoder;
-- // run some decoding
--
-- while (newstate->decode_codec->m_samples_used <= 0)
-- {
-- int l=fread(newstate->decode_codec->DecodeGetSrcBuffer(128),1,128,newstate->decode_fp);
-- if (l) newstate->decode_codec->DecodeWrote(l);
-- if (!l)
-- {
-- clearerr(newstate->decode_fp);
-- break;
-- }
-- }
-- }
--
-- return newstate;
--}
--
--float NJClient::GetOutputPeak()
--{
-- return (float)output_peaklevel;
--}
--
--void NJClient::ChatMessage_Send(char *parm1, char *parm2, char *parm3, char *parm4, char *parm5)
--{
-- if (m_netcon)
-- {
-- mpb_chat_message m;
-- m.parms[0]=parm1;
-- m.parms[1]=parm2;
-- m.parms[2]=parm3;
-- m.parms[3]=parm4;
-- m.parms[4]=parm5;
-- m_netcon->Send(m.build());
-- }
--}
--
--void NJClient::process_samples(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate, int offset, int justmonitor)
--{
-- // -36dB/sec
-- double decay=pow(.25*0.25*0.25,len/(double)srate);
-- // encode my audio and send to server, if enabled
-- int u;
-- m_locchan_cs.Enter();
-- for (u = 0; u < m_locchannels.GetSize() && u < m_max_localch; u ++)
-- {
-- Local_Channel *lc=m_locchannels.Get(u);
-- int sc=lc->src_channel;
-- float *src=NULL;
-- if (sc >= 0 && sc < innch) src=inbuf[sc]+offset;
--
-- if (lc->cbf || !src || ChannelMixer)
-- {
-- int bytelen=len*(int)sizeof(float);
-- if (tmpblock.GetSize() < bytelen) tmpblock.Resize(bytelen);
--
-- if (ChannelMixer && ChannelMixer(ChannelMixer_User32,inbuf,offset,innch,sc,(float*)tmpblock.Get(),len))
-- {
-- // channelmixer succeeded
-- }
-- else if (src) memcpy(tmpblock.Get(),src,bytelen);
-- else memset(tmpblock.Get(),0,bytelen);
--
-- src=(float* )tmpblock.Get();
--
-- // processor
-- if (lc->cbf)
-- {
-- lc->cbf(src,len,lc->cbf_inst);
-- }
-- }
--
-- if (!justmonitor && lc->bcast_active)
-- {
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- lc->m_bq.AddBlock(src,len);
--#endif
-- }
--
--
-- // monitor this channel
-- if ((!m_issoloactive && !lc->muted) || lc->solo)
-- {
-- float *out1=outbuf[0]+offset;
--
-- float vol1=lc->volume;
-- if (outnch > 1)
-- {
-- float vol2=vol1;
-- float *out2=outbuf[1]+offset;
-- if (lc->pan > 0.0f) vol1 *= 1.0f-lc->pan;
-- else if (lc->pan < 0.0f) vol2 *= 1.0f+lc->pan;
--
-- float maxf=(float) (lc->decode_peak_vol*decay);
--
-- int x=len;
-- while (x--)
-- {
-- float f=src[0] * vol1;
--
-- if (f > maxf) maxf=f;
-- else if (f < -maxf) maxf=-f;
--
-- if (f > 1.0) f=1.0;
-- else if (f < -1.0) f=-1.0;
--
-- *out1++ += f;
--
-- f=src[0]*vol2;
--
-- if (f > maxf) maxf=f;
-- else if (f < -maxf) maxf=-f;
--
-- if (f > 1.0) f=1.0;
-- else if (f < -1.0) f=-1.0;
--
-- *out2++ += f;
-- src++;
-- }
-- lc->decode_peak_vol=maxf;
-- }
-- else
-- {
-- float maxf=(float) (lc->decode_peak_vol*decay);
-- int x=len;
-- while (x--)
-- {
-- float f=*src++ * vol1;
-- if (f > maxf) maxf=f;
-- else if (f < -maxf) maxf=-f;
--
-- if (f > 1.0) f=1.0;
-- else if (f < -1.0) f=-1.0;
--
-- *out1++ += f;
-- }
-- lc->decode_peak_vol=maxf;
-- }
-- }
-- else lc->decode_peak_vol=0.0;
-- }
--
-- m_locchan_cs.Leave();
--
--
-- if (!justmonitor)
-- {
-- // mix in all active (subscribed) channels
-- m_users_cs.Enter();
-- for (u = 0; u < m_remoteusers.GetSize(); u ++)
-- {
-- RemoteUser *user=m_remoteusers.Get(u);
-- int ch;
-- if (!user) continue;
--
-- for (ch = 0; ch < MAX_USER_CHANNELS; ch ++)
-- {
-- float lpan=user->pan+user->channels[ch].pan;
-- if (lpan<-1.0)lpan=-1.0;
-- else if (lpan>1.0)lpan=1.0;
--
-- bool muteflag;
-- if (m_issoloactive) muteflag = !(user->solomask & (1<<ch));
-- else muteflag=(user->mutedmask & (1<<ch)) || user->muted;
--
-- if (user->channels[ch].ds)
-- mixInChannel(muteflag,
-- user->volume*user->channels[ch].volume,lpan,
-- user->channels[ch].ds,outbuf,len,srate,outnch,offset,decay);
-- }
-- }
-- m_users_cs.Leave();
--
--
-- // write out wave if necessary
--
-- if (waveWrite
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- ||(m_oggWrite&&m_oggComp)
--#endif
-- )
-- {
-- m_wavebq->AddBlock(outbuf[0]+offset,len,outbuf[outnch>1]+offset);
-- }
-- }
--
-- // apply master volume, then
-- {
-- int x=len;
-- float *ptr1=outbuf[0]+offset;
-- float maxf=(float)(output_peaklevel*decay);
--
-- if (outnch >= 2)
-- {
-- float *ptr2=outbuf[1]+offset;
-- float vol1=config_mastermute?0.0f:config_mastervolume;
-- float vol2=vol1;
-- if (config_masterpan > 0.0f) vol1 *= 1.0f-config_masterpan;
-- else if (config_masterpan< 0.0f) vol2 *= 1.0f+config_masterpan;
--
-- while (x--)
-- {
-- float f = *ptr1++ *= vol1;
-- if (f > maxf) maxf=f;
-- else if (f < -maxf) maxf=-f;
--
-- f = *ptr2++ *= vol2;
-- if (f > maxf) maxf=f;
-- else if (f < -maxf) maxf=-f;
-- }
-- }
-- else
-- {
-- float vol1=config_mastermute?0.0f:config_mastervolume;
-- while (x--)
-- {
-- float f = *ptr1++ *= vol1;
-- if (f > maxf) maxf=f;
-- else if (f < -maxf) maxf=-f;
-- }
-- }
-- output_peaklevel=maxf;
-- }
--
-- // mix in (super shitty) metronome (fucko!!!!)
-- if (!justmonitor)
-- {
-- int metrolen=srate / 100;
-- double sc=6000.0/(double)srate;
-- int x;
-- int um=config_metronome>0.0001f;
-- double vol1=config_metronome_mute?0.0:config_metronome,vol2=vol1;
-- float *ptr1=outbuf[0]+offset;
-- float *ptr2=NULL;
-- if (outnch > 1)
-- {
-- ptr2=outbuf[1]+offset;
-- if (config_metronome_pan > 0.0f) vol1 *= 1.0f-config_metronome_pan;
-- else if (config_metronome_pan< 0.0f) vol2 *= 1.0f+config_metronome_pan;
-- }
-- for (x = 0; x < len; x ++)
-- {
-- if (m_metronome_pos <= 0.0)
-- {
-- m_metronome_state=1;
-- m_metronome_tmp=(m_interval_pos+x)<m_metronome_interval;
-- m_metronome_pos += (double)m_metronome_interval;
-- }
-- m_metronome_pos-=1.0;
--
-- if (m_metronome_state>0)
-- {
-- if (um)
-- {
-- double val=0.0;
-- if (!m_metronome_tmp) val = sin((double)m_metronome_state*sc*2.0) * 0.25;
-- else val = sin((double)m_metronome_state*sc);
--
-- ptr1[x]+=(float)(val*vol1);
-- if (ptr2) ptr2[x]+=(float)(val*vol2);
-- }
-- if (++m_metronome_state >= metrolen) m_metronome_state=0;
--
-- }
-- }
-- }
--
--}
--
--void NJClient::mixInChannel(bool muted, float vol, float pan, DecodeState *chan, float **outbuf, int len, int srate, int outnch, int offs, double vudecay)
--{
-- if (!chan->decode_codec || !chan->decode_fp) return;
--
-- int needed;
-- while (chan->decode_codec->m_samples_used <=
-- (needed=resampleLengthNeeded(chan->decode_codec->GetSampleRate(),srate,len,&chan->resample_state)*chan->decode_codec->GetNumChannels()))
-- {
-- int l=fread(chan->decode_codec->DecodeGetSrcBuffer(128),1,128,chan->decode_fp);
-- chan->decode_codec->DecodeWrote(l);
-- if (!l)
-- {
-- clearerr(chan->decode_fp);
-- break;
-- }
-- }
--
-- if (chan->decode_codec->m_samples_used >= needed+chan->dump_samples)
-- {
-- float *sptr=(float *)chan->decode_codec->m_samples.Get();
--
-- // process VU meter, yay for powerful CPUs
-- if (!muted && vol > 0.0000001)
-- {
-- float *p=sptr;
-- int l=(needed+chan->dump_samples)*chan->decode_codec->GetNumChannels();
-- float maxf=(float) (chan->decode_peak_vol*vudecay/vol);
-- while (l--)
-- {
-- float f=*p++;
-- if (f > maxf) maxf=f;
-- else if (f < -maxf) maxf=-f;
-- }
-- chan->decode_peak_vol=maxf*vol;
--
-- float *tmpbuf[2]={outbuf[0]+offs,outnch > 1 ? (outbuf[1]+offs) : 0};
-- mixFloatsNIOutput(sptr+chan->dump_samples,
-- chan->decode_codec->GetSampleRate(),
-- chan->decode_codec->GetNumChannels(),
-- tmpbuf,
-- srate,outnch>1?2:1,len,
-- vol,pan,&chan->resample_state);
-- }
-- else
-- chan->decode_peak_vol=0.0;
--
-- // advance the queue
-- chan->decode_samplesout += needed/chan->decode_codec->GetNumChannels();
-- chan->decode_codec->m_samples_used -= needed+chan->dump_samples;
-- memcpy(sptr,sptr+needed+chan->dump_samples,chan->decode_codec->m_samples_used*sizeof(float));
-- chan->dump_samples=0;
-- }
-- else
-- {
--
-- if (config_debug_level>0)
-- {
-- static int cnt=0;
--
-- char s[512];
-- guidtostr(chan->guid,s);
--
-- char buf[512];
-- sprintf(buf,"underrun %d at %d on %s, %d/%d samples\n",cnt++,ftell(chan->decode_fp),s,chan->decode_codec->m_samples_used,needed);
--#ifdef _WIN32
-- OutputDebugString(buf);
--#endif
-- }
--
-- chan->decode_samplesout += chan->decode_codec->m_samples_used/chan->decode_codec->GetNumChannels();
-- chan->decode_codec->m_samples_used=0;
-- chan->dump_samples+=needed;
--
-- }
--}
--
--void NJClient::on_new_interval()
--{
-- m_loopcnt++;
-- writeLog("interval %d %.2f %d\n",m_loopcnt,GetActualBPM(),m_active_bpi);
--
-- m_metronome_pos=0.0;
--
-- int u;
-- m_locchan_cs.Enter();
-- for (u = 0; u < m_locchannels.GetSize() && u < m_max_localch; u ++)
-- {
-- Local_Channel *lc=m_locchannels.Get(u);
--
--
-- if (lc->bcast_active)
-- {
-- lc->m_bq.AddBlock(NULL,0);
-- }
--
-- int wasact=lc->bcast_active;
--
-- lc->bcast_active = lc->broadcasting;
--
-- if (wasact && !lc->bcast_active)
-- {
-- lc->m_bq.AddBlock(NULL,-1);
-- }
--
-- }
-- m_locchan_cs.Leave();
--
-- m_users_cs.Enter();
-- for (u = 0; u < m_remoteusers.GetSize(); u ++)
-- {
-- RemoteUser *user=m_remoteusers.Get(u);
-- int ch;
--// printf("submask=%d,cpm=%d\n",user->submask , user->chanpresentmask);
-- for (ch = 0; ch < MAX_USER_CHANNELS; ch ++)
-- {
-- RemoteUser_Channel *chan=&user->channels[ch];
-- delete chan->ds;
-- chan->ds=0;
-- if ((user->submask & user->chanpresentmask) & (1<<ch)) chan->ds = chan->next_ds[0];
-- else delete chan->next_ds[0];
-- chan->next_ds[0]=chan->next_ds[1]; // advance queue
-- chan->next_ds[1]=0;
-- ;
-- if (chan->ds)
-- {
-- char guidstr[64];
-- guidtostr(chan->ds->guid,guidstr);
-- writeLog("user %s \"%s\" %d \"%s\"\n",guidstr,user->name.Get(),ch,chan->name.Get());
-- }
-- }
-- }
-- m_users_cs.Leave();
--
-- //if (m_enc->isError()) printf("ERROR\n");
-- //else printf("YAY\n");
--
--}
--
--
--char *NJClient::GetUserState(int idx, float *vol, float *pan, bool *mute)
--{
-- if (idx<0 || idx>=m_remoteusers.GetSize()) return NULL;
-- RemoteUser *p=m_remoteusers.Get(idx);
-- if (vol) *vol=p->volume;
-- if (pan) *pan=p->pan;
-- if (mute) *mute=p->muted;
-- return p->name.Get();
--}
--
--void NJClient::SetUserState(int idx, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute)
--{
-- if (idx<0 || idx>=m_remoteusers.GetSize()) return;
-- RemoteUser *p=m_remoteusers.Get(idx);
-- if (setvol) p->volume=vol;
-- if (setpan) p->pan=pan;
-- if (setmute) p->muted=mute;
--}
--
--int NJClient::EnumUserChannels(int useridx, int i)
--{
-- if (useridx<0 || useridx>=m_remoteusers.GetSize()||i<0||i>=MAX_USER_CHANNELS) return -1;
-- RemoteUser *user=m_remoteusers.Get(useridx);
--
-- int x;
-- for (x = 0; x < 32; x ++)
-- {
-- if ((user->chanpresentmask & (1<<x)) && !i--) return x;
-- }
-- return -1;
--}
--
--char *NJClient::GetUserChannelState(int useridx, int channelidx, bool *sub, float *vol, float *pan, bool *mute, bool *solo)
--{
-- if (useridx<0 || useridx>=m_remoteusers.GetSize()||channelidx<0||channelidx>=MAX_USER_CHANNELS) return NULL;
-- RemoteUser_Channel *p=m_remoteusers.Get(useridx)->channels + channelidx;
-- RemoteUser *user=m_remoteusers.Get(useridx);
-- if (!(user->chanpresentmask & (1<<channelidx))) return 0;
--
-- if (sub) *sub=!!(user->submask & (1<<channelidx));
-- if (vol) *vol=p->volume;
-- if (pan) *pan=p->pan;
-- if (mute) *mute=!!(user->mutedmask & (1<<channelidx));
-- if (solo) *solo=!!(user->solomask & (1<<channelidx));
--
-- return p->name.Get();
--}
--
--
--void NJClient::SetUserChannelState(int useridx, int channelidx,
-- bool setsub, bool sub, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo)
--{
-- if (useridx<0 || useridx>=m_remoteusers.GetSize()||channelidx<0||channelidx>=MAX_USER_CHANNELS) return;
-- RemoteUser *user=m_remoteusers.Get(useridx);
-- RemoteUser_Channel *p=user->channels + channelidx;
-- if (!(user->chanpresentmask & (1<<channelidx))) return;
--
-- if (setsub && !!(user->submask&(1<<channelidx)) != sub)
-- {
-- // toggle subscription
-- if (!sub)
-- {
-- mpb_client_set_usermask su;
-- su.build_add_rec(user->name.Get(),(user->submask&=~(1<<channelidx)));
-- m_netcon->Send(su.build());
--
-- DecodeState *tmp,*tmp2,*tmp3;
-- m_users_cs.Enter();
-- tmp=p->ds; p->ds=0;
-- tmp2=p->next_ds[0]; p->next_ds[0]=0;
-- tmp3=p->next_ds[1]; p->next_ds[1]=0;
-- m_users_cs.Leave();
--
-- delete tmp;
-- delete tmp2;
-- delete tmp3;
-- }
-- else
-- {
-- mpb_client_set_usermask su;
-- su.build_add_rec(user->name.Get(),(user->submask|=(1<<channelidx)));
-- m_netcon->Send(su.build());
-- }
--
-- }
-- if (setvol) p->volume=vol;
-- if (setpan) p->pan=pan;
-- if (setmute)
-- {
-- if (mute)
-- user->mutedmask |= (1<<channelidx);
-- else
-- user->mutedmask &= ~(1<<channelidx);
-- }
-- if (setsolo)
-- {
-- if (solo) user->solomask |= (1<<channelidx);
-- else user->solomask &= ~(1<<channelidx);
--
-- if (user->solomask) m_issoloactive|=1;
-- else
-- {
-- int x;
-- for (x = 0; x < m_remoteusers.GetSize(); x ++)
-- {
-- if (m_remoteusers.Get(x)->solomask)
-- break;
-- }
-- if (x == m_remoteusers.GetSize()) m_issoloactive&=~1;
-- }
-- }
--}
--
--
--float NJClient::GetUserChannelPeak(int useridx, int channelidx)
--{
-- if (useridx<0 || useridx>=m_remoteusers.GetSize()||channelidx<0||channelidx>=MAX_USER_CHANNELS) return 0.0f;
-- RemoteUser_Channel *p=m_remoteusers.Get(useridx)->channels + channelidx;
-- RemoteUser *user=m_remoteusers.Get(useridx);
-- if (!(user->chanpresentmask & (1<<channelidx))) return 0.0f;
-- if (!p->ds) return 0.0f;
--
-- return (float)p->ds->decode_peak_vol;
--}
--
--float NJClient::GetLocalChannelPeak(int ch)
--{
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x == m_locchannels.GetSize()) return 0.0f;
-- Local_Channel *c=m_locchannels.Get(x);
-- return (float)c->decode_peak_vol;
--}
--
--void NJClient::DeleteLocalChannel(int ch)
--{
-- m_locchan_cs.Enter();
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x < m_locchannels.GetSize())
-- {
-- delete m_locchannels.Get(x);
-- m_locchannels.Delete(x);
-- }
-- m_locchan_cs.Leave();
--}
--
--void NJClient::SetLocalChannelProcessor(int ch, void (*cbf)(float *, int ns, void *), void *inst)
--{
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x < m_locchannels.GetSize())
-- {
-- m_locchan_cs.Enter();
-- Local_Channel *c=m_locchannels.Get(x);
-- c->cbf=cbf;
-- c->cbf_inst=inst;
-- m_locchan_cs.Leave();
-- }
--}
--
--void NJClient::GetLocalChannelProcessor(int ch, void **func, void **inst)
--{
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x == m_locchannels.GetSize())
-- {
-- if (func) *func=0;
-- if (inst) *inst=0;
-- return;
-- }
--
-- Local_Channel *c=m_locchannels.Get(x);
-- if (func) *func=(void *)c->cbf;
-- if (inst) *inst=c->cbf_inst;
--}
--
--void NJClient::SetLocalChannelInfo(int ch, char *name, bool setsrcch, int srcch,
-- bool setbitrate, int bitrate, bool setbcast, bool broadcast)
--{
-- m_locchan_cs.Enter();
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x == m_locchannels.GetSize())
-- {
-- m_locchannels.Add(new Local_Channel);
-- }
--
-- Local_Channel *c=m_locchannels.Get(x);
-- c->channel_idx=ch;
-- if (name) c->name.Set(name);
-- if (setsrcch) c->src_channel=srcch;
-- if (setbitrate) c->bitrate=bitrate;
-- if (setbcast) c->broadcasting=broadcast;
-- m_locchan_cs.Leave();
--}
--
--char *NJClient::GetLocalChannelInfo(int ch, int *srcch, int *bitrate, bool *broadcast)
--{
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x == m_locchannels.GetSize()) return 0;
-- Local_Channel *c=m_locchannels.Get(x);
-- if (srcch) *srcch=c->src_channel;
-- if (bitrate) *bitrate=c->bitrate;
-- if (broadcast) *broadcast=c->broadcasting;
--
-- return c->name.Get();
--}
--
--int NJClient::EnumLocalChannels(int i)
--{
-- if (i<0||i>=m_locchannels.GetSize()) return -1;
-- return m_locchannels.Get(i)->channel_idx;
--}
--
--
--void NJClient::SetLocalChannelMonitoring(int ch, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo)
--{
-- m_locchan_cs.Enter();
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x == m_locchannels.GetSize())
-- {
-- m_locchannels.Add(new Local_Channel);
-- }
--
-- Local_Channel *c=m_locchannels.Get(x);
-- c->channel_idx=ch;
-- if (setvol) c->volume=vol;
-- if (setpan) c->pan=pan;
-- if (setmute) c->muted=mute;
-- if (setsolo)
-- {
-- c->solo = solo;
-- if (solo) m_issoloactive|=2;
-- else
-- {
-- int x;
-- for (x = 0; x < m_locchannels.GetSize(); x ++)
-- {
-- if (m_locchannels.Get(x)->solo) break;
-- }
-- if (x == m_locchannels.GetSize())
-- m_issoloactive&=~2;
-- }
-- }
-- m_locchan_cs.Leave();
--}
--
--int NJClient::GetLocalChannelMonitoring(int ch, float *vol, float *pan, bool *mute, bool *solo)
--{
-- int x;
-- for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-- if (x == m_locchannels.GetSize()) return -1;
-- Local_Channel *c=m_locchannels.Get(x);
-- if (vol) *vol=c->volume;
-- if (pan) *pan=c->pan;
-- if (mute) *mute=c->muted;
-- if (solo) *solo=c->solo;
-- return 0;
--}
--
--
--
--void NJClient::NotifyServerOfChannelChange()
--{
-- if (m_netcon)
-- {
-- int x;
-- mpb_client_set_channel_info sci;
-- for (x = 0; x < m_locchannels.GetSize(); x ++)
-- {
-- Local_Channel *ch=m_locchannels.Get(x);
-- sci.build_add_rec(ch->name.Get(),0,0,0);
-- }
-- m_netcon->Send(sci.build());
-- }
--}
--
--void NJClient::SetWorkDir(char *path)
--{
-- m_workdir.Set(path?path:"");
--
-- if (!path || !*path) return;
--
--
-- if (path[0] && path[strlen(path)-1] != '/' && path[strlen(path)-1] != '\\')
--#ifdef _WIN32
-- m_workdir.Append("\\");
--#else
-- m_workdir.Append("/");
--#endif
--
-- // create subdirectories for ogg files
-- int a;
-- for (a = 0; a < 16; a ++)
-- {
-- WDL_String tmp(m_workdir.Get());
-- char buf[5];
-- sprintf(buf,"%x",a);
-- tmp.Append(buf);
--#ifdef _WIN32
-- CreateDirectory(tmp.Get(),NULL);
--#else
-- mkdir(tmp.Get(),0700);
--#endif
-- }
--}
--
--
--RemoteUser_Channel::RemoteUser_Channel() : volume(1.0f), pan(0.0f), ds(NULL)
--{
-- memset(next_ds,0,sizeof(next_ds));
--}
--
--RemoteUser_Channel::~RemoteUser_Channel()
--{
-- delete ds;
-- ds=NULL;
-- delete next_ds[0];
-- delete next_ds[1];
-- memset(next_ds,0,sizeof(next_ds));
--}
--
--
--RemoteDownload::RemoteDownload() : chidx(-1), playtime(0), fp(0)
--{
-- memset(&guid,0,sizeof(guid));
-- time(&last_time);
--}
--
--RemoteDownload::~RemoteDownload()
--{
-- Close();
--}
--
--void RemoteDownload::Close()
--{
-- if (fp) fclose(fp);
-- fp=0;
-- startPlaying(1);
--}
--
--void RemoteDownload::Open(NJClient *parent, unsigned int fourcc)
--{
-- m_parent=parent;
-- Close();
-- WDL_String s;
-- parent->makeFilenameFromGuid(&s,guid);
--
--
-- // append extension from fourcc
-- char buf[8];
-- type_to_string(fourcc, buf);
-- s.Append(".");
-- s.Append(buf);
--
-- m_fourcc=fourcc;
-- fp=fopen(s.Get(),"wb");
--}
--
--void RemoteDownload::startPlaying(int force)
--{
-- if (m_parent && chidx >= 0 && (force || (playtime && fp && ftell(fp)>playtime)))
-- // wait until we have config_play_prebuffer of data to start playing, or if config_play_prebuffer is 0, we are forced to play (download finished)
-- {
-- int x;
-- RemoteUser *theuser;
-- for (x = 0; x < m_parent->m_remoteusers.GetSize() && strcmp((theuser=m_parent->m_remoteusers.Get(x))->name.Get(),username.Get()); x ++);
-- if (x < m_parent->m_remoteusers.GetSize() && chidx >= 0 && chidx < MAX_USER_CHANNELS)
-- {
-- DecodeState *tmp=m_parent->start_decode(guid,m_fourcc);
--
-- DecodeState *tmp2;
-- m_parent->m_users_cs.Enter();
-- int useidx=!!theuser->channels[chidx].next_ds[0];
-- tmp2=theuser->channels[chidx].next_ds[useidx];
-- theuser->channels[chidx].next_ds[useidx]=tmp;
-- m_parent->m_users_cs.Leave();
-- delete tmp2;
-- }
-- chidx=-1;
-- }
--}
--
--void RemoteDownload::Write(void *buf, int len)
--{
-- int pos=len;
-- if (fp)
-- {
-- fwrite(buf,1,len,fp);
-- fflush(fp);
-- pos = ftell(fp);
-- }
--
-- startPlaying();
--}
--
--
--Local_Channel::Local_Channel() : channel_idx(0), src_channel(0), volume(1.0f), pan(0.0f),
-- muted(false), solo(false), broadcasting(false),
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- m_enc(NULL),
-- m_enc_bitrate_used(0),
-- m_enc_header_needsend(NULL),
--#endif
-- bcast_active(false), cbf(NULL), cbf_inst(NULL),
-- bitrate(64), m_need_header(true), m_wavewritefile(NULL),
-- decode_peak_vol(0.0)
--{
--}
--
--
--int BufferQueue::GetBlock(WDL_HeapBuf **b) // return 0 if got one, 1 if none avail
--{
-- m_cs.Enter();
-- if (m_samplequeue.Available())
-- {
-- *b=*(WDL_HeapBuf **)m_samplequeue.Get();
-- m_samplequeue.Advance(sizeof(WDL_HeapBuf *));
-- if (m_samplequeue.Available()<256) m_samplequeue.Compact();
-- m_cs.Leave();
-- return 0;
-- }
-- m_cs.Leave();
-- return 1;
--}
--
--void BufferQueue::DisposeBlock(WDL_HeapBuf *b)
--{
-- m_cs.Enter();
-- if (b && (int)b != -1) m_emptybufs.Add(b);
-- m_cs.Leave();
--}
--
--
--void BufferQueue::AddBlock(float *samples, int len, float *samples2)
--{
-- WDL_HeapBuf *mybuf=0;
-- if (len>0)
-- {
-- m_cs.Enter();
--
-- if (m_samplequeue.Available() > 512)
-- {
-- m_cs.Leave();
-- return;
-- }
-- int tmp;
-- if ((tmp=m_emptybufs.GetSize()))
-- {
-- mybuf=m_emptybufs.Get(tmp-1);
-- if (mybuf) m_emptybufs.Delete(tmp-1);
-- }
-- m_cs.Leave();
-- if (!mybuf) mybuf=new WDL_HeapBuf;
--
-- int uselen=len*sizeof(float);
-- if (samples2)
-- {
-- uselen+=uselen;
-- }
--
-- mybuf->Resize(uselen);
--
-- memcpy(mybuf->Get(),samples,len*sizeof(float));
-- if (samples2)
-- memcpy((float*)mybuf->Get()+len,samples2,len*sizeof(float));
-- }
-- else if (len == -1) mybuf=(WDL_HeapBuf *)-1;
--
-- m_cs.Enter();
-- m_samplequeue.Add(&mybuf,sizeof(mybuf));
-- m_cs.Leave();
--}
--
--Local_Channel::~Local_Channel()
--{
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- delete m_enc;
-- m_enc=0;
-- delete m_enc_header_needsend;
-- m_enc_header_needsend=0;
--#endif
--
-- delete m_wavewritefile;
-- m_wavewritefile=0;
--
--}
--
--void NJClient::SetOggOutFile(FILE *fp, int srate, int nch, int bitrate)
--{
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- if (m_oggWrite)
-- {
-- if (m_oggComp)
-- {
-- m_oggComp->Encode(NULL,0);
-- if (m_oggComp->outqueue.Available())
-- fwrite((char *)m_oggComp->outqueue.Get(),1,m_oggComp->outqueue.Available(),m_oggWrite);
-- }
-- fclose(m_oggWrite);
-- m_oggWrite=0;
-- }
-- delete m_oggComp;
-- m_oggComp=0;
--
-- if (fp)
-- {
-- //fucko
-- m_oggComp=new I_NJEncoder(srate,nch,bitrate,WDL_RNG_int32());
-- m_oggWrite=fp;
-- }
--#endif
--}
--
-diff -Naur ninjam-cclient-0.01a/ninjam/njclient.h ninjam/ninjam/njclient.h
---- ninjam-cclient-0.01a/ninjam/njclient.h 2005-08-30 03:16:06.000000000 +0000
-+++ ninjam/ninjam/njclient.h 1970-01-01 00:00:00.000000000 +0000
-@@ -1,263 +0,0 @@
--/*
-- NINJAM - njclient.h
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- This file defines the interface for the NJClient class, which handles
-- the bulk of logic and state of the client.
--
-- The basic premise of the NJClient class is, the UI code tells NJClient
-- when the user tweaks something, and NJClient tells the UI code when
-- it needs to update something.
--
-- NJClient::Run() needs to be called regularly (preferably every 50ms or less).
-- When calling, if Run() returns 0, you should immediately call it again. i.e.:
--
-- while (!myClient->Run());
--
-- Is how Run() should usually be called. In general it is easier to call Run()
-- from the UI thread in a timer, for example, but it turns out it's a lot better
-- to call it from its own thread to ensure that some UI issue doesn't end up
-- stalling it. If you go this route, you will want to put the Run() call inside
-- of a mutex lock, and also any code that reads/writes remote channel state or
-- writes to local channel state, in that mutex lock as well. This is a bit of
-- a pain, but not really that bad.
--
-- Additionally, NJClient::AudioProc() needs to be called from the audio thread.
-- It is not necessary to do any sort of mutex protection around these calls,
-- though, as they are done internally.
--
--
-- Some other notes:
--
-- + Currently only OGG Vorbis is supported. There's hooks in there to add support
-- for more formats, but the requirements for the formats are a little high, so
-- currently OGG Vorbis is the only thing we've seen that would work well. And it
-- really rocks for this application.
--
-- + OK maybe that's it for now? :)
--
--*/
--
--#ifndef _NJCLIENT_H_
--#define _NJCLIENT_H_
--
--#ifdef _WIN32
--#include <windows.h>
--#else
--#include <stdlib.h>
--#include <memory.h>
--#endif
--#include <stdio.h>
--#include <time.h>
--#include "../WDL/string.h"
--#include "../WDL/ptrlist.h"
--#include "../WDL/jnetlib/jnetlib.h"
--#include "../WDL/sha.h"
--#include "../WDL/rng.h"
--#include "../WDL/mutex.h"
--
--#include "../WDL/wavwrite.h"
--
--#include "netmsg.h"
--
--
--class I_NJEncoder;
--class RemoteDownload;
--class RemoteUser;
--class Local_Channel;
--class DecodeState;
--class BufferQueue;
--
--// #define NJCLIENT_NO_XMIT_SUPPORT // might want to do this for njcast :)
--// it also removes mixed ogg writing support
--
--class NJClient
--{
-- friend class RemoteDownload;
--public:
-- NJClient();
-- ~NJClient();
--
-- void Connect(char *host, char *user, char *pass);
-- void Disconnect();
--
-- // call Run() from your main (UI) thread
-- int Run();// returns nonzero if sleep is OK
--
-- char *GetErrorStr() { return m_errstr.Get(); }
--
-- int IsAudioRunning() { return m_audio_enable; }
-- // call AudioProc, (and only AudioProc) from your audio thread
-- void AudioProc(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate); // len is number of sample pairs or samples
--
--
-- // basic configuration
-- int config_autosubscribe;
-- int config_savelocalaudio; // set 1 to save compressed files, set to 2 to save .wav files as well.
-- // -1 makes it try to delete the remote .oggs as soon as possible
--
-- float config_metronome,config_metronome_pan; // volume of metronome
-- bool config_metronome_mute;
-- float config_mastervolume,config_masterpan; // master volume
-- bool config_mastermute;
-- int config_debug_level;
-- int config_play_prebuffer; // -1 means play instantly, 0 means play when full file is there, otherwise refers to how many
-- // bytes of compressed source to have before play. the default value is 4096.
--
-- float GetOutputPeak();
--
-- enum { NJC_STATUS_DISCONNECTED=-3,NJC_STATUS_INVALIDAUTH=-2, NJC_STATUS_CANTCONNECT=-1, NJC_STATUS_OK=0, NJC_STATUS_PRECONNECT};
-- int GetStatus();
--
-- void SetWorkDir(char *path);
-- char *GetWorkDir() { return m_workdir.Get(); }
--
-- char *GetUserName() { return m_user.Get(); }
-- char *GetHostName() { return m_host.Get(); }
--
-- float GetActualBPM() { return (float) m_active_bpm; }
-- int GetBPI() { return m_active_bpi; }
-- void GetPosition(int *pos, int *length); // positions in samples
-- int GetLoopCount() { return m_loopcnt; }
-- unsigned int GetSessionPosition(); // returns milliseconds
--
-- int HasUserInfoChanged() { if (m_userinfochange) { m_userinfochange=0; return 1; } return 0; }
-- int GetNumUsers() { return m_remoteusers.GetSize(); }
-- char *GetUserState(int idx, float *vol=0, float *pan=0, bool *mute=0);
-- void SetUserState(int idx, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute);
--
-- float GetUserChannelPeak(int useridx, int channelidx);
-- char *GetUserChannelState(int useridx, int channelidx, bool *sub=0, float *vol=0, float *pan=0, bool *mute=0, bool *solo=0);
-- void SetUserChannelState(int useridx, int channelidx, bool setsub, bool sub, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo);
-- int EnumUserChannels(int useridx, int i); // returns <0 if out of channels. start with i=0, and go upwards
--
-- int GetMaxLocalChannels() { return m_max_localch; }
-- void DeleteLocalChannel(int ch);
-- int EnumLocalChannels(int i);
-- float GetLocalChannelPeak(int ch);
-- void SetLocalChannelProcessor(int ch, void (*cbf)(float *, int ns, void *), void *inst);
-- void GetLocalChannelProcessor(int ch, void **func, void **inst);
-- void SetLocalChannelInfo(int ch, char *name, bool setsrcch, int srcch, bool setbitrate, int bitrate, bool setbcast, bool broadcast);
-- char *GetLocalChannelInfo(int ch, int *srcch, int *bitrate, bool *broadcast);
-- void SetLocalChannelMonitoring(int ch, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo);
-- int GetLocalChannelMonitoring(int ch, float *vol, float *pan, bool *mute, bool *solo); // 0 on success
-- void NotifyServerOfChannelChange(); // call after any SetLocalChannel* that occur after initial connect
--
-- int IsASoloActive() { return m_issoloactive; }
--
-- void SetLogFile(char *name=NULL);
--
-- void SetOggOutFile(FILE *fp, int srate, int nch, int bitrate=128);
-- WaveWriter *waveWrite;
--
--
-- int LicenseAgreement_User32;
-- int (*LicenseAgreementCallback)(int user32, char *licensetext); // return TRUE if user accepts
--
--
-- // messages you can send:
-- // "MSG" "text" - broadcast "text" to everybody
-- // "PRIVMSG" "username" "text" - send text to "username"
-- void ChatMessage_Send(char *parm1, char *parm2, char *parm3=NULL, char *parm4=NULL, char *parm5=NULL);
--
-- // messages you can receive from this:
-- // "MSG" "user" "text" - message from user to everybody (including you!), or if user is empty, from the server
-- // "PRIVMSG "user" "text" - private message from user
--
-- // usernames are not case sensitive, but message names ARE.
--
-- // note that nparms is the MAX number of parms, you still can get NULL parms entries in there (though rarely)
-- void (*ChatMessage_Callback)(int user32, NJClient *inst, char **parms, int nparms);
-- int ChatMessage_User32;
--
--
-- // set these if you want to mix multiple channels into the output channel
-- // return 0 if you want the default behavior
-- int (*ChannelMixer)(int user32, float **inbuf, int in_offset, int innch, int chidx, float *outbuf, int len);
-- int ChannelMixer_User32;
--
--
--protected:
-- double output_peaklevel;
--
-- void _reinit();
--
-- void makeFilenameFromGuid(WDL_String *s, unsigned char *guid);
--
-- void updateBPMinfo(int bpm, int bpi);
-- void process_samples(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate, int offset, int justmonitor=0);
-- void on_new_interval();
--
-- void writeLog(char *fmt, ...);
--
-- WDL_String m_errstr;
--
-- WDL_String m_workdir;
-- int m_status;
-- int m_max_localch;
-- int m_connection_keepalive;
-- FILE *m_logFile;
--#ifndef NJCLIENT_NO_XMIT_SUPPORT
-- FILE *m_oggWrite;
-- I_NJEncoder *m_oggComp;
--#endif
--
-- WDL_String m_user, m_pass, m_host;
--
-- int m_in_auth;
-- int m_bpm,m_bpi;
-- int m_beatinfo_updated;
-- int m_audio_enable;
-- int m_srate;
-- int m_userinfochange;
-- int m_issoloactive;
--
-- unsigned int m_session_pos_ms,m_session_pos_samples; // samples just keeps track of any samples lost to precision errors
--
-- int m_loopcnt;
-- int m_active_bpm, m_active_bpi;
-- int m_interval_length;
-- int m_interval_pos, m_metronome_state, m_metronome_tmp,m_metronome_interval;
-- double m_metronome_pos;
--
-- DecodeState *start_decode(unsigned char *guid, unsigned int fourcc=0);
--
-- BufferQueue *m_wavebq;
--
-- WDL_PtrList<Local_Channel> m_locchannels;
--
-- void mixInChannel(bool muted, float vol, float pan, DecodeState *chan, float **outbuf, int len, int srate, int outnch, int offs, double vudecay);
--
-- WDL_Mutex m_users_cs, m_locchan_cs, m_log_cs, m_misc_cs;
-- Net_Connection *m_netcon;
-- WDL_PtrList<RemoteUser> m_remoteusers;
-- WDL_PtrList<RemoteDownload> m_downloads;
--
-- WDL_HeapBuf tmpblock;
--};
--
--
--
--#define MAX_USER_CHANNELS 32
--#define MAX_LOCAL_CHANNELS 32 // probably want to use NJClient::GetMaxLocalChannels() if determining when it's OK to add a channel,etc
--#define DOWNLOAD_TIMEOUT 8
--
--
--#endif//_NJCLIENT_H_
-diff -Naur ninjam-cclient-0.01a/ninjam/njmisc.cpp ninjam/ninjam/njmisc.cpp
---- ninjam-cclient-0.01a/ninjam/njmisc.cpp 2005-08-30 03:16:07.000000000 +0000
-+++ ninjam/ninjam/njmisc.cpp 1970-01-01 00:00:00.000000000 +0000
-@@ -1,155 +0,0 @@
--/*
-- NINJAM - njmisc.cpp
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--
--/*
--
-- Some utility functions common to clients.
--
--*/
--
--
--#ifdef _WIN32
--#include <windows.h>
--#endif
--
--#include <string.h>
--#include <stdio.h>
--#include <math.h>
--#include <float.h>
--
--#include "njmisc.h"
--
--// dB related utilities
--
--double DB2SLIDER(double x)
--{
-- double d=pow(2110.54*fabs(x),1.0/3.0);
-- if (x < 0.0) d=-d;
-- return d + 63.0;
--}
--
--double SLIDER2DB(double y)
--{
-- return pow(y-63.0,3.0) * (1.0/2110.54);
--}
--
--double VAL2DB(double x)
--{
-- static double g_ilog2x6;
-- static int a;
-- if (!a)
-- {
-- a++;
-- g_ilog2x6 = 6.0/log10(2.0);
-- }
-- double v=(log10(x)*g_ilog2x6);
-- if (v < -120.0) v=-120.0;
-- return v;
--}
--
--void mkvolpanstr(char *str, double vol, double pan)
--{
-- mkvolstr(str,vol);
-- char *p=str+strlen(str);
-- *p++=' ';
-- mkpanstr(p,pan);
--}
--
--void mkpanstr(char *str, double pan)
--{
-- if (fabs(pan) < 0.0001) strcpy(str,"center");
-- else sprintf(str,"%d%%%s", (int)fabs(pan*100.0),(pan>0.0 ? "R" : "L"));
--}
--
--void mkvolstr(char *str, double vol)
--{
-- double v=VAL2DB(vol);
-- if (vol < 0.0000001 || v < -120.0) v=-120.0;
-- sprintf(str,"%s%2.1fdB",v>0.0?"+":"",v);
--}
--
--
--
--/// jesusonic interfacing
--
--#ifdef _WIN32
--
--void deleteJesusonicProc(void *i, int chi)
--{
-- if (JesusonicAPI && i)
-- {
-- char buf[4096];
-- sprintf(buf,"%s\\ninjam.p%02d",jesusdir.Get()[0]?jesusdir.Get():".",chi);
-- JesusonicAPI->preset_save(i,buf);
-- JesusonicAPI->ui_wnd_destroy(i);
-- JesusonicAPI->set_opts(i,-1,-1,1);
-- JesusonicAPI->ui_quit(i);
-- JesusonicAPI->destroyInstance(i);
-- }
--}
--
--
--void jesusonic_processor(float *buf, int len, void *inst)
--{
-- if (inst)
-- {
-- _controlfp(_RC_CHOP,_MCW_RC);
-- JesusonicAPI->jesus_process_samples(inst,(char*)buf,len*sizeof(float));
-- JesusonicAPI->osc_run(inst,(char*)buf,len);
-- }
--}
--
--
--void JesusUpdateInfo(void *myInst, char *chdesc, int srate)
--{
-- if (myInst)
-- {
-- JesusonicAPI->set_sample_fmt(myInst,srate,1,33);
-- WDL_String tmp("NINJAM embedded: ");
-- tmp.Append(chdesc);
-- JesusonicAPI->set_status(myInst,"",tmp.Get());
-- }
--}
--
--void *CreateJesusInstance(int a, char *chdesc, int srate)
--{
-- if (JesusonicAPI)
-- {
-- void *myInst=JesusonicAPI->createInstance();
-- if (!myInst) return 0;
-- JesusonicAPI->set_rootdir(myInst,jesusdir.Get());
-- JesusonicAPI->ui_init(myInst);
-- JesusonicAPI->set_opts(myInst,1,1,-1);
--
-- JesusUpdateInfo(myInst,chdesc,srate);
--
-- char buf[4096];
-- sprintf(buf,"%s\\ninjam.p%02d",jesusdir.Get()[0]?jesusdir.Get():".",a);
--
-- JesusonicAPI->preset_load(myInst,buf);
--
-- return (void *)myInst;
-- }
-- return 0;
--}
--
--
--
--#endif
-\ Kein Zeilenumbruch am Dateiende.
-diff -Naur ninjam-cclient-0.01a/ninjam/njmisc.h ninjam/ninjam/njmisc.h
---- ninjam-cclient-0.01a/ninjam/njmisc.h 2005-08-30 03:16:07.000000000 +0000
-+++ ninjam/ninjam/njmisc.h 1970-01-01 00:00:00.000000000 +0000
-@@ -1,54 +0,0 @@
--/*
-- NINJAM - njmisc.h
-- Copyright (C) 2005 Cockos Incorporated
--
-- NINJAM 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.
--
-- NINJAM 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 NINJAM; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--/*
--
-- Some utility functions common to clients.
--
--*/
--
--#ifndef _NJMISC_H_
--#define _NJMISC_H_
--
--// some utility functions
--double DB2SLIDER(double x);
--double SLIDER2DB(double y);
--double VAL2DB(double x);
--#define DB2VAL(x) (pow(2.0,(x)/6.0))
--void mkvolpanstr(char *str, double vol, double pan);
--void mkvolstr(char *str, double vol);
--void mkpanstr(char *str, double pan);
--
--#ifdef _WIN32
--
--#include "../../WDL/string.h"
--#include "../../jesusonic/jesusonic_dll.h"
--
--extern WDL_String jesusdir;
--extern jesusonicAPI *JesusonicAPI;
--
--void *CreateJesusInstance(int a, char *chdesc, int srate);
--void JesusUpdateInfo(void *myInst, char *chdesc, int srate);
--void deleteJesusonicProc(void *i, int chi);
--void jesusonic_processor(float *buf, int len, void *inst);
--
--
--#endif
--
--#endif
-\ Kein Zeilenumbruch am Dateiende.
-diff -Naur ninjam-cclient-0.01a/src/audiostream_alsa.cpp ninjam/src/audiostream_alsa.cpp
---- ninjam-cclient-0.01a/src/audiostream_alsa.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/audiostream_alsa.cpp 2005-08-30 21:49:14.000000000 +0000
-@@ -0,0 +1,430 @@
-+/*
-+ NINJAM - audiostream_alsa.cpp
-+ Copyright (C) 2004-2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This file implements a audioStreamer that uses ALSA.
-+ It only exposes the following functions:
-+
-+ audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc);
-+
-+ cfg is a string that has a list of parameter/value pairs (space delimited)
-+ for the config:
-+ in - input device i.e. hw:0,0
-+ out - output device i.e. hw:0,0
-+ srate - sample rate i.e. 48000
-+ bps - bits/sample i.e. 16
-+ nch - channels i.e. 2
-+ bsize - block size (bytes) i.e. 2048
-+ nblock - number of blocks i.e. 16
-+
-+
-+ (everything else in this file is used internally)
-+
-+*/
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <errno.h>
-+
-+#include <signal.h>
-+#include <unistd.h>
-+#include <fcntl.h>
-+#include <pthread.h>
-+
-+#include <alsa/asoundlib.h>
-+#include <sys/ioctl.h>
-+#include <sys/soundcard.h>
-+
-+#include "../WDL/pcmfmtcvt.h"
-+
-+#include "../WDL/ptrlist.h"
-+#include "audiostream.h"
-+
-+static void audiostream_onunder() { }
-+static void audiostream_onover() { }
-+
-+
-+
-+class audioStreamer_int
-+{
-+ public:
-+ audioStreamer_int() { m_srate=48000; m_nch=2; m_bps=16; }
-+ virtual ~audioStreamer_int() { }
-+
-+ virtual int Read(char *buf, int len)=0; // returns 0 if blocked, < 0 if error, > 0 if data
-+ virtual int Write(char *buf, int len)=0; // returns 0 on success
-+
-+ int m_srate, m_nch, m_bps;
-+};
-+
-+
-+
-+class audioStreamer_ALSA : public audioStreamer_int
-+{
-+ public:
-+ audioStreamer_ALSA();
-+ ~audioStreamer_ALSA();
-+ int Open(char *devname, int is_write, int srate, int nch, int bps, int fragsize, int nfrags, int dosleep);
-+
-+ int Read(char *buf, int len); // returns 0 if blocked, < 0 if error, > 0 if data
-+ int Write(char *buf, int len); // returns 0 on success
-+ private:
-+ snd_pcm_t *pcm_handle;
-+ int m_sleep;
-+ int m_bufsize;
-+ int m_nfrags;
-+ int m_started;
-+};
-+
-+
-+
-+//////////////// ALSA driver
-+audioStreamer_ALSA::audioStreamer_ALSA()
-+{
-+ m_started=0;
-+ pcm_handle=NULL;
-+ m_bufsize=1000000;
-+}
-+
-+audioStreamer_ALSA::~audioStreamer_ALSA()
-+{
-+ if (pcm_handle)
-+ {
-+ snd_pcm_drop(pcm_handle);
-+ snd_pcm_close(pcm_handle);
-+ }
-+}
-+
-+int audioStreamer_ALSA::Open(char *devname, int is_write, int srate, int nch, int bps, int fragsize, int nfrags, int dosleep)
-+{
-+ m_sleep=dosleep;
-+
-+ /* Playback stream */
-+ snd_pcm_stream_t stream = is_write?SND_PCM_STREAM_PLAYBACK:SND_PCM_STREAM_CAPTURE;
-+
-+ /* This structure contains information about */
-+ /* the hardware and can be used to specify the */
-+ /* configuration to be used for the PCM stream. */
-+ snd_pcm_hw_params_t *hwparams;
-+
-+ /* Allocate the snd_pcm_hw_params_t structure on the stack. */
-+ snd_pcm_hw_params_alloca(&hwparams);
-+
-+ if (snd_pcm_open(&pcm_handle, devname, stream, 0) < 0)
-+ {
-+ fprintf(stderr, "Error opening PCM device %s\n", devname);
-+ return(-1);
-+ }
-+
-+ /* Init hwparams with full configuration space */
-+ if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0)
-+ {
-+ fprintf(stderr, "Can not configure this PCM device.\n");
-+ return(-1);
-+ }
-+
-+ if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
-+ {
-+ fprintf(stderr, "Error setting access.\n");
-+ return(-1);
-+ }
-+
-+ /* Set sample format */
-+ m_bps=bps==32?32:bps==24?24:16;
-+ if (snd_pcm_hw_params_set_format(pcm_handle, hwparams,
-+ bps==32?SND_PCM_FORMAT_S32_LE:bps==24?SND_PCM_FORMAT_S24_3LE:SND_PCM_FORMAT_S16_LE) < 0) {
-+ fprintf(stderr, "Error setting format.\n");
-+ fprintf(stderr, "Try -bps 16, -bps 24, or -bps 32\n");
-+ return(-1);
-+ }
-+
-+ int dir=0; /* exact_rate == rate --> dir = 0 */
-+ /* exact_rate < rate --> dir = -1 */
-+ /* exact_rate > rate --> dir = 1 */
-+ unsigned int usrate=srate;
-+
-+ /* Set sample rate. If the exact rate is not supported */
-+ /* by the hardware, use nearest possible rate. */
-+ m_srate=srate;
-+ int exact_rate = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &usrate, &dir);
-+ if (dir != 0)
-+ {
-+ fprintf(stderr, "The rate %d Hz is not supported by your hardware. Using %d Hz instead.\n", srate, exact_rate);
-+ m_srate=exact_rate;
-+ }
-+
-+ /* Set number of channels */
-+ if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, nch) < 0)
-+ {
-+ fprintf(stderr, "Error setting channels.\n");
-+ fprintf(stderr, "Try -nch 1 or -nch 2\n");
-+ return(-1);
-+ }
-+ m_nch=nch;
-+
-+ int periods=m_nfrags=(is_write?nfrags:nfrags*3);
-+ int periodsize=fragsize;
-+
-+ /* Set number of periods. Periods used to be called fragments. */
-+ if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0)
-+ {
-+ fprintf(stderr, "Error setting periods.\n");
-+ fprintf(stderr, "Try -nbufs 2 through -nbufs 16\n");
-+ return(-1);
-+ }
-+
-+ /* Set buffer size (in frames). The resulting latency is given by */
-+ /* latency = periodsize * periods / (rate * bytes_per_frame) */
-+ if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, m_bufsize = (periodsize * periods)/(m_nch * m_bps/8)) < 0)
-+ {
-+ fprintf(stderr, "Error setting buffersize.\n");
-+ fprintf(stderr, "Try -bufsize 256 through -bufsize 2048\n");
-+ return(-1);
-+ }
-+
-+ /* Apply HW parameter settings to */
-+ /* PCM device and prepare device */
-+ if (snd_pcm_hw_params(pcm_handle, hwparams) < 0)
-+ {
-+ fprintf(stderr, "Error setting HW params.\n");
-+ return(-1);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+int audioStreamer_ALSA::Read(char *buf, int len) // returns 0 if blocked, < 0 if error, > 0 if data
-+{
-+ int ret;
-+ if (m_sleep >= 0)
-+ {
-+ struct pollfd pfds[32];
-+ int cnt=snd_pcm_poll_descriptors(pcm_handle,pfds,32);
-+ if (cnt>0) poll(pfds,cnt,m_sleep);
-+ }
-+
-+ ret=snd_pcm_readi(pcm_handle, buf, len/(m_nch*(m_bps/8)));
-+
-+ if (ret < 0)
-+ {
-+ if (ret != -EAGAIN) { snd_pcm_prepare(pcm_handle); }
-+ return 0;
-+ }
-+#if 0
-+ snd_pcm_sframes_t del=0;
-+ if (!snd_pcm_delay(pcm_handle,&del) && del > m_bufsize/2 /* JF>used to be /1 */)
-+ {
-+ audiostream_onover();
-+ for (;;) if (snd_pcm_readi(pcm_handle, buf, len/(m_nch*(m_bps/8)))<0) break;
-+ // we have too many samples, eat some
-+ }
-+#endif
-+
-+ return ret*m_nch*(m_bps/8);
-+}
-+
-+
-+int audioStreamer_ALSA::Write(char *buf, int len) // returns 0 on success
-+{
-+ snd_pcm_sframes_t del=0;
-+ if (!len) return 0;
-+
-+ int cnt=1;
-+ if (!m_started || !snd_pcm_delay(pcm_handle,&del) && del<1)
-+ {
-+ if (m_started) audiostream_onunder();
-+ else m_started=1;
-+ cnt=m_nfrags;
-+ memset(buf,0,len); // reduce noise
-+
-+ }
-+
-+ while (cnt-->0)
-+ {
-+ int ret=snd_pcm_writei(pcm_handle, buf, len/(m_nch*(m_bps/8)));
-+ if (ret < 0)
-+ {
-+ if (ret == -EPIPE) snd_pcm_prepare(pcm_handle);
-+ return 0;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+
-+
-+//============== asio simulation shit
-+//
-+class audioStreamer_asiosim : public audioStreamer
-+{
-+ public:
-+ audioStreamer_asiosim(audioStreamer_int *i, audioStreamer_int *o, int bufsize, int srate, int bps, SPLPROC proc)
-+ {
-+ m_splproc=proc;
-+ in=i;
-+ out=o;
-+ m_bps=bps;
-+ m_innch=m_outnch=2;
-+ m_bps=bps;
-+ m_srate=srate;
-+ m_done=0;
-+ m_buf=(char *)malloc(bufsize);
-+ m_bufsize=bufsize;
-+
-+ m_procbuf=(float *)malloc((bufsize*64)/bps);// allocated 2x, input and output
-+
-+
-+ // create thread
-+ pthread_create(&hThread,NULL,threadProc,(void *)this);
-+ }
-+ ~audioStreamer_asiosim()
-+ {
-+ m_done=1;
-+
-+ // kill thread
-+ pthread_join(hThread,NULL);
-+
-+ delete in;
-+ delete out;
-+ free(m_buf);
-+ free(m_procbuf);
-+ }
-+
-+ const char *GetChannelName(int idx)
-+ {
-+ if (idx == 0) return "Left";
-+ if (idx == 1) return "Right";
-+ return NULL;
-+ }
-+
-+ private:
-+ void tp();
-+ static void *threadProc(void *p)
-+ {
-+ audioStreamer_asiosim *t=(audioStreamer_asiosim*)p;
-+ t->tp();
-+ return 0;
-+ }
-+ audioStreamer_int *in, *out;
-+
-+ pthread_t hThread;
-+ int m_done,m_bufsize;
-+ char *m_buf;
-+ float *m_procbuf;
-+
-+ SPLPROC m_splproc;
-+};
-+
-+void audioStreamer_asiosim::tp()
-+{
-+ while (!m_done)
-+ {
-+ int a=in->Read(m_buf,m_bufsize);
-+ if (a>0)
-+ {
-+ int spllen=a*4/(m_bps); // a*8/m_bps/nch
-+ float *inptrs[2], *outptrs[2];
-+ inptrs[0]=m_procbuf;
-+ inptrs[1]=m_procbuf+spllen;
-+ outptrs[0]=m_procbuf+spllen*2;
-+ outptrs[1]=m_procbuf+spllen*3;
-+
-+ pcmToFloats(m_buf,spllen,m_bps,2,inptrs[0],1);
-+ pcmToFloats(m_buf+(m_bps/8),spllen,m_bps,2,inptrs[1],1);
-+
-+ if (m_splproc) m_splproc(inptrs,2,outptrs,2,spllen,m_srate);
-+
-+ floatsToPcm(outptrs[0],1,spllen,m_buf,m_bps,2);
-+ floatsToPcm(outptrs[1],1,spllen,m_buf+(m_bps/8),m_bps,2);
-+
-+ out->Write(m_buf,a);
-+ }
-+ else
-+ {
-+ struct timespec s={0,1000*1000}; // sleep 1ms;
-+ nanosleep(&s,NULL);
-+ }
-+ }
-+}
-+
-+audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc)
-+{
-+ // todo: parse from cfg
-+ char *indev="hw:0,0";
-+ char *outdev="hw:0,0";
-+ int srate=48000;
-+ int nch=2;
-+ int bps=16;
-+ int fs=1024;
-+ int nf=16;
-+
-+ while (cfg && *cfg)
-+ {
-+ char *p=cfg;
-+ while (*p && *p != ' ') p++;
-+ if (!*p) break;
-+ *p++=0;
-+ while (*p == ' ') p++;
-+ if (!*p)
-+ {
-+ printf("config item '%s' has no parameter\n",cfg);
-+ return 0;
-+ }
-+
-+ if (!strcasecmp(cfg,"in")) indev=p;
-+ else if (!strcasecmp(cfg,"out")) outdev=p;
-+ else if (!strcasecmp(cfg,"srate")) srate=atoi(p);
-+ else if (!strcasecmp(cfg,"nch")) nch=atoi(p);
-+ else if (!strcasecmp(cfg,"bps")) bps=atoi(p);
-+ else if (!strcasecmp(cfg,"bsize")) fs=atoi(p);
-+ else if (!strcasecmp(cfg,"nblock")) nf=atoi(p);
-+ else
-+ {
-+ printf("unknown config item '%s'\n",cfg);
-+ return 0;
-+ }
-+
-+ while (*p && *p != ' ') p++;
-+ if (!*p) break;
-+ *p++=0;
-+ while (*p == ' ') p++;
-+ cfg=p;
-+ }
-+
-+ audioStreamer_ALSA *in=new audioStreamer_ALSA();
-+ if (in->Open(indev,0,srate,nch,bps,fs,nf,-1))
-+ {
-+ delete in;
-+ return 0;
-+ }
-+ audioStreamer_ALSA *out=new audioStreamer_ALSA();
-+ if (out->Open(outdev,1,srate,nch,bps,fs,nf,-1))
-+ {
-+ delete in;
-+ delete out;
-+ return 0;
-+ }
-+
-+ return new audioStreamer_asiosim(in,out,fs,srate,bps,proc);
-+}
-diff -Naur ninjam-cclient-0.01a/src/audiostream.h ninjam/src/audiostream.h
---- ninjam-cclient-0.01a/src/audiostream.h 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/audiostream.h 2006-01-09 18:57:21.000000000 +0000
-@@ -0,0 +1,72 @@
-+/*
-+ NINJAM - audiostream.h
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This header is used by NINJAM clients to define an abstract audio streamer interface, as
-+ well as declare functions for creating instances of these audio streamers.
-+
-+ On Windows, these functions are primarily called from audioconfig.cpp, and on
-+ the Cocoa client the function is called from Controller.mm.
-+
-+ The basic structure is:
-+
-+ The client runs, creates an audiostreamer (below), giving it a SPLPROC, which is it's
-+ own function that then in turn calls NJClient::AudioProc.
-+
-+ But this is just the interface declaration etc.
-+
-+*/
-+
-+#ifndef _AUDIOSTREAM_H_
-+#define _AUDIOSTREAM_H_
-+
-+
-+class audioStreamer
-+{
-+ public:
-+ audioStreamer() { m_srate=48000; m_outnch=m_innch=2; m_bps=16; }
-+ virtual ~audioStreamer() { }
-+
-+ virtual const char *GetChannelName(int idx)=0;
-+
-+ int m_srate, m_innch, m_outnch, m_bps;
-+};
-+
-+
-+typedef void (*SPLPROC)(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate);
-+
-+
-+#ifdef _WIN32
-+audioStreamer *create_audioStreamer_KS(int srate, int bps, int *nbufs, int *bufsize, SPLPROC proc);
-+
-+audioStreamer *create_audioStreamer_WO(int srate, int bps, int devs[2], int *nbufs, int *bufsize, SPLPROC proc);
-+audioStreamer *create_audioStreamer_DS(int srate, int bps, GUID devs[2], int *nbufs, int *bufsize, SPLPROC proc);
-+
-+#else
-+
-+#ifdef _MAC
-+audioStreamer *create_audioStreamer_CoreAudio(char **dev, int srate, int nch, int bps, SPLPROC proc);
-+#else
-+audioStreamer *create_audioStreamer_JACK(char *cfg, SPLPROC proc);
-+#endif
-+
-+#endif
-+
-+#endif
-diff -Naur ninjam-cclient-0.01a/src/audiostream_jack.cpp ninjam/src/audiostream_jack.cpp
---- ninjam-cclient-0.01a/src/audiostream_jack.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/audiostream_jack.cpp 2006-01-09 21:37:06.000000000 +0000
-@@ -0,0 +1,142 @@
-+/*
-+ NINJAM - audiostream_alsa.cpp
-+ Copyright (C) 2004-2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This file implements a audioStreamer that uses ALSA.
-+ It only exposes the following functions:
-+
-+ audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc);
-+
-+ cfg is a string that has a list of parameter/value pairs (space delimited)
-+ for the config:
-+ in - input device i.e. hw:0,0
-+ out - output device i.e. hw:0,0
-+ srate - sample rate i.e. 48000
-+ bps - bits/sample i.e. 16
-+ nch - channels i.e. 2
-+ bsize - block size (bytes) i.e. 2048
-+ nblock - number of blocks i.e. 16
-+
-+
-+ (everything else in this file is used internally)
-+
-+*/
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <errno.h>
-+
-+#include <signal.h>
-+#include <unistd.h>
-+#include <fcntl.h>
-+#include <pthread.h>
-+
-+#include <jack/jack.h>
-+
-+#include "../WDL/pcmfmtcvt.h"
-+
-+#include "../WDL/ptrlist.h"
-+#include "audiostream.h"
-+
-+static void audiostream_onunder() { }
-+static void audiostream_onover() { }
-+
-+
-+
-+
-+
-+class audioStreamer_JACK : public audioStreamer
-+{
-+ public:
-+ audioStreamer_JACK( char *cfg, SPLPROC proc );
-+ ~audioStreamer_JACK();
-+
-+ int process( jack_nframes_t nframes );
-+ const char *GetChannelName(int idx)
-+ {
-+ if (idx == 0) return "Left";
-+ if (idx == 1) return "Right";
-+ return NULL;
-+ }
-+ private:
-+ jack_client_t *client;
-+ jack_port_t *in1, *in2;
-+ jack_port_t *out1, *out2;
-+
-+ SPLPROC splproc;
-+};
-+
-+
-+int
-+process_cb( jack_nframes_t nframes, audioStreamer_JACK *as ) {
-+ return as->process( nframes );
-+}
-+
-+
-+//////////////// ALSA driver
-+audioStreamer_JACK::audioStreamer_JACK( char *cfg, SPLPROC proc)
-+{
-+
-+ splproc = proc;
-+
-+ if ((client = jack_client_new ("ninjam")) == 0) {
-+ fprintf (stderr, "jack server not running?\n");
-+ exit(20);
-+ }
-+
-+ jack_set_process_callback (client, (JackProcessCallback) process_cb, this);
-+
-+
-+ out1 = jack_port_register (client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
-+ out2 = jack_port_register (client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
-+
-+ in1 = jack_port_register (client, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
-+ in2 = jack_port_register (client, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
-+
-+ if (jack_activate (client)) {
-+ fprintf (stderr, "cannot activate client");
-+ exit(20);
-+ }
-+}
-+
-+audioStreamer_JACK::~audioStreamer_JACK()
-+{
-+ jack_deactivate( client );
-+ sleep(1);
-+}
-+
-+int
-+audioStreamer_JACK::process( jack_nframes_t nframes ) {
-+ float *inports[2];
-+ float *outports[2];
-+
-+ inports[0] = (float *) jack_port_get_buffer( in1, nframes );
-+ inports[1] = (float *) jack_port_get_buffer( in2, nframes );
-+ outports[0] = (float *) jack_port_get_buffer( out1, nframes );
-+ outports[1] = (float *) jack_port_get_buffer( out2, nframes );
-+
-+ splproc( inports, 2, outports, 2, nframes, jack_get_sample_rate( client ) );
-+ return 0;
-+}
-+
-+audioStreamer *create_audioStreamer_JACK(char *cfg, SPLPROC proc)
-+{
-+ return new audioStreamer_JACK( cfg, proc);
-+}
-diff -Naur ninjam-cclient-0.01a/src/audiostream_mac.cpp ninjam/src/audiostream_mac.cpp
---- ninjam-cclient-0.01a/src/audiostream_mac.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/audiostream_mac.cpp 2005-08-30 03:16:06.000000000 +0000
-@@ -0,0 +1,474 @@
-+/*
-+ NINJAM Mac OS X Clients - audiostream_mac.cpp
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This file implements the audioStream interface for CoreAudio devices.
-+
-+*/
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <errno.h>
-+
-+#include <signal.h>
-+#include <unistd.h>
-+#include <fcntl.h>
-+
-+#include "audiostream.h"
-+
-+static SPLPROC _splproc;
-+
-+#include </System/Library/Frameworks/CoreAudio.framework/Headers/AudioHardware.h>
-+
-+
-+class audioStreamer_CoreAudio : public audioStreamer
-+{
-+ public:
-+
-+ audioStreamer_CoreAudio();
-+ ~audioStreamer_CoreAudio();
-+ int Open(char **dev, int srate, int nch, int bps);
-+ int Read(char *buf, int len); // returns 0 if blocked, < 0 if error, > 0 if data
-+ int Write(char *buf, int len); // returns 0 on success
-+ const char *GetChannelName(int idx)
-+ {
-+ if (idx < 0 || idx >= m_innch) return NULL;
-+ static char buf[128];
-+ sprintf(buf,"Channel %d",idx+1);
-+ return buf;
-+ }
-+
-+
-+ private:
-+
-+ AudioDeviceID m_myDev_i;
-+ AudioDeviceID m_myDev_o;
-+ int m_started;
-+
-+};
-+
-+
-+#include <sys/stat.h>
-+#include <pthread.h>
-+
-+#include "../WDL/queue.h"
-+
-+static int outchtab[2]={0,1};
-+
-+static int g_srate;
-+
-+// this is a total hack until I spend the time and make a good multichannel CoreAudio implementation.
-+static WDL_HeapBuf spltemp;
-+
-+// this takes the interleaved samples in, and puts them in their own buffers,
-+// and processes, then reinterleaves
-+static void onsamples_old(float *inbuf, int innch, float *outbuf, int outnch, int nsamples, int srate)
-+{
-+ float **inptrs = (float **)alloca(sizeof(float *)*innch);
-+ int sz=nsamples*sizeof(float)*(innch+2);
-+ if (spltemp.GetSize() < sz) spltemp.Resize(sz);
-+ int x;
-+ float *t=(float*)spltemp.Get();
-+ for (x = 0; x < innch; x ++)
-+ {
-+ float *s=inbuf+x;
-+ inptrs[x]=t;
-+ int y=nsamples;
-+ while (y--)
-+ {
-+ *t++ = *s;
-+ s += innch;
-+ }
-+ }
-+ float *outptrs[2]={t,t+nsamples};
-+
-+ if (_splproc) _splproc(inptrs,innch,outptrs,2,nsamples,srate);
-+
-+ float *p1=outptrs[0];
-+ float *p2=outptrs[1];
-+ x=nsamples;
-+ if (outnch > 0)
-+ {
-+ while (x--)
-+ {
-+ outbuf[outchtab[0]]=*p1++;
-+ if (outnch > 1) outbuf[outchtab[1]]=*p2++;
-+ outbuf += outnch;
-+ }
-+ }
-+ else
-+ {
-+ outnch=-outnch;
-+ while (x--)
-+ {
-+ outbuf[0]=*p1++;
-+ if (outnch > 1) outbuf[1]=*p2++;
-+ outbuf += outnch;
-+ }
-+ }
-+
-+}
-+
-+static pthread_mutex_t m_mutex;
-+static WDL_Queue m_splbuf;
-+static int inchbuf=0;
-+static int outchbuf=0;
-+static float *ca_tmpbuf;
-+static int ca_tmpbuf_size;
-+
-+OSStatus caIOproc(AudioDeviceID dev,
-+ const AudioTimeStamp* inNow,
-+ const AudioBufferList* inInputData,
-+ const AudioTimeStamp* inInputTime,
-+ AudioBufferList* outOutputData,
-+ const AudioTimeStamp* inOutputTime,
-+ void* inClientData)
-+{
-+ // process inInputData to outOutputData
-+ if (inInputData && outOutputData)
-+ {
-+ int in_size=inInputData->mBuffers[inchbuf].mDataByteSize;
-+ char *in=(char *)inInputData->mBuffers[inchbuf].mData;
-+ int in_nch = inInputData->mBuffers[inchbuf].mNumberChannels;
-+
-+ int out_size=outOutputData->mBuffers[outchbuf].mDataByteSize;
-+ char *out=(char *)outOutputData->mBuffers[outchbuf].mData;
-+ int out_nch = outOutputData->mBuffers[outchbuf].mNumberChannels;
-+
-+ if (in_size*out_nch == out_size*in_nch) // faster than a divide
-+ {
-+ int needsize=((in_size/in_nch) * 2);
-+ if (!ca_tmpbuf || ca_tmpbuf_size < needsize) ca_tmpbuf=(float*)realloc(ca_tmpbuf,ca_tmpbuf_size=needsize);
-+ if (ca_tmpbuf)
-+ {
-+ int c=in_size/(sizeof(float)*in_nch);
-+ onsamples_old((float*)in,in_nch,(float *)out,out_nch,c,g_srate);
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+OSStatus caInproc(AudioDeviceID dev,
-+ const AudioTimeStamp* inNow,
-+ const AudioBufferList* inInputData,
-+ const AudioTimeStamp* inInputTime,
-+ AudioBufferList* outOutputData,
-+ const AudioTimeStamp* inOutputTime,
-+ void* inClientData)
-+{
-+ // process inInputData to outOutputData
-+ if (inInputData)
-+ {
-+ int in_size=inInputData->mBuffers[inchbuf].mDataByteSize;
-+ char *in=(char *)inInputData->mBuffers[inchbuf].mData;
-+ int in_nch = inInputData->mBuffers[inchbuf].mNumberChannels;
-+
-+ {
-+ int needsize=((in_size/in_nch) * 2);
-+ if (!ca_tmpbuf || ca_tmpbuf_size < needsize) ca_tmpbuf=(float*)realloc(ca_tmpbuf,ca_tmpbuf_size=needsize);
-+ if (ca_tmpbuf)
-+ {
-+ if (m_splbuf.GetSize() < 48000*8)
-+ {
-+ int c=in_size/(sizeof(float)*in_nch);
-+ onsamples_old((float*)in,in_nch,(float *)ca_tmpbuf,-2,c,g_srate);
-+
-+ pthread_mutex_lock(&m_mutex);
-+
-+ m_splbuf.Add(ca_tmpbuf,needsize);
-+
-+ pthread_mutex_unlock(&m_mutex);
-+ }
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+OSStatus caOutproc(AudioDeviceID dev,
-+ const AudioTimeStamp* inNow,
-+ const AudioBufferList* inInputData,
-+ const AudioTimeStamp* inInputTime,
-+ AudioBufferList* outOutputData,
-+ const AudioTimeStamp* inOutputTime,
-+ void* inClientData)
-+{
-+ // process inInputData to outOutputData
-+ if (outOutputData)
-+ {
-+ int out_size=outOutputData->mBuffers[outchbuf].mDataByteSize;
-+ char *out=(char *)outOutputData->mBuffers[outchbuf].mData;
-+ int out_nch = outOutputData->mBuffers[outchbuf].mNumberChannels;
-+
-+ pthread_mutex_lock(&m_mutex);
-+ if (out_size < m_splbuf.Available())
-+ {
-+ float *fin=(float *)m_splbuf.Get();
-+ float *fout=(float *)out;
-+ int x,c=out_size/(sizeof(float)*out_nch);
-+ for (x = 0; x < c; x ++)
-+ {
-+ fout[outchtab[0]]=*fin++;
-+ fout[outchtab[1]]=*fin++;
-+ fout += out_nch;
-+ }
-+ m_splbuf.Advance(out_size);
-+ m_splbuf.Compact();
-+ }
-+ pthread_mutex_unlock(&m_mutex);
-+ }
-+ return 0;
-+}
-+
-+audioStreamer_CoreAudio::audioStreamer_CoreAudio()
-+{
-+ m_myDev_i=0;
-+ m_myDev_o=0;
-+ m_started=0;
-+}
-+
-+audioStreamer_CoreAudio::~audioStreamer_CoreAudio()
-+{
-+ if (m_started)
-+ {
-+ if (m_myDev_o != m_myDev_i)
-+ {
-+ AudioDeviceStop(m_myDev_i,caInproc);
-+ AudioDeviceRemoveIOProc(m_myDev_i,caInproc);
-+ AudioDeviceStop(m_myDev_o,caOutproc);
-+ AudioDeviceRemoveIOProc(m_myDev_o,caOutproc);
-+ }
-+ else
-+ {
-+ AudioDeviceStop(m_myDev_i,caIOproc);
-+ AudioDeviceRemoveIOProc(m_myDev_i,caIOproc);
-+ }
-+ }
-+
-+}
-+
-+
-+int matchlen(const char *sub, const char *pa)
-+{
-+ int l=0;
-+ while (*sub && *pa && toupper(*sub) == toupper(*pa)) { sub++; pa++; l++; }
-+ return l;
-+}
-+
-+int audioStreamer_CoreAudio::Open(char **dev, int srate, int nch, int bps)
-+{
-+ pthread_mutex_init(&m_mutex,NULL);
-+ char *olddev= *dev;
-+ m_srate=g_srate=srate;
-+ m_bps=33;
-+ m_innch=m_outnch=2;
-+#ifndef AUDIOSTREAMER_NO_CONSOLEUI
-+ char user_buf[512];
-+#endif
-+
-+
-+ UInt32 theSize;
-+ int s = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &theSize, NULL );
-+ int theNumberDevices = theSize / sizeof(AudioDeviceID);
-+ if (!theNumberDevices)
-+ {
-+ printf("No CoreAudio devices found!\n");
-+ return -1;
-+ }
-+ AudioDeviceID *list=(AudioDeviceID *)malloc(sizeof(AudioDeviceID)*theNumberDevices);
-+ AudioHardwareGetProperty(kAudioHardwarePropertyDevices,&theSize,list);
-+
-+
-+again:
-+
-+ char *indev_ptr=olddev?olddev:(char *)"";
-+ char *outdev_ptr=strstr(indev_ptr,",");
-+ if (outdev_ptr)
-+ {
-+ *outdev_ptr++=0;
-+ while (*outdev_ptr == ' ') outdev_ptr++;
-+ if (!*outdev_ptr) outdev_ptr=indev_ptr;
-+ } else outdev_ptr=indev_ptr;
-+
-+ int outm=0,inm=0;
-+ printf("CoreAudio device list:\n");
-+ for (s = 0; s < theNumberDevices; s ++)
-+ {
-+ AudioDeviceID myDev;
-+ myDev = list[s];
-+ UInt32 os=0;
-+ Boolean ow;
-+ AudioDeviceGetPropertyInfo(myDev,0,0,kAudioDevicePropertyDeviceName,&os,&ow);
-+ if (os > 0)
-+ {
-+ char *buf=(char *)malloc(os+1);
-+
-+ AudioDeviceGetProperty(myDev,0,0,kAudioDevicePropertyDeviceName,&os,buf);
-+ if (os > 0)
-+ {
-+ int flags=0;
-+ int i;
-+
-+ for (i = 0; i <2; i ++)
-+ {
-+ UInt32 nos=0; Boolean now;
-+ AudioDeviceGetPropertyInfo(myDev,0,i,kAudioDevicePropertyStreamConfiguration,&nos,&now);
-+ if (nos>=sizeof(AudioBufferList))
-+ {
-+ AudioBufferList *buf2=(AudioBufferList *)malloc(nos);
-+ AudioDeviceGetProperty(myDev,0,i,kAudioDevicePropertyStreamConfiguration,&nos,buf2);
-+ if (nos>=sizeof(AudioBufferList))
-+ {
-+ flags |= 1<<i;
-+ }
-+ free(buf2);
-+ }
-+ }
-+ int ml=(flags & 2) ? matchlen(indev_ptr,buf) : 0;
-+ if (ml > inm) { inm=ml; m_myDev_i = myDev; }
-+ ml=(flags & 1) ? matchlen(outdev_ptr,buf) : 0;
-+ if (ml > outm) { outm=ml; m_myDev_o = myDev; }
-+
-+ printf(" '%s' %s%s%s",buf,flags&2?"Input":"",flags==3?"/":"",flags&1?"Output":"");
-+
-+ }
-+
-+ printf("\n");
-+ free(buf);
-+ }
-+ }
-+
-+ if (!m_myDev_i || !m_myDev_o)
-+ {
-+ #ifndef AUDIOSTREAMER_NO_CONSOLEUI
-+ printf("Type in the beginning of the name of your sound hardware now (or leave blank for system defaults)\n");
-+ printf("Note: to specify different input/output hardware, use device1, device2\n");
-+ printf("Choice: ");
-+ fflush(stdout);
-+ user_buf[0]=0;
-+ fgets(user_buf,sizeof(user_buf),stdin);
-+ olddev=user_buf;
-+ if (user_buf[0] && user_buf[0] != '\r' && user_buf[0] != '\n')
-+ {
-+ goto again;
-+ }
-+ #endif
-+ UInt32 theSize=sizeof(AudioDeviceID);
-+ if (!m_myDev_i) AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,&theSize,&m_myDev_i);
-+ theSize=sizeof(AudioDeviceID);
-+ if (!m_myDev_o) AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,&theSize,&m_myDev_o);
-+ }
-+
-+
-+ free(list);
-+
-+ int isinput;
-+ for (isinput=0;isinput<2;isinput++)
-+ {
-+ AudioDeviceID myDev = isinput ? m_myDev_i : m_myDev_o;
-+
-+ UInt32 os=0;
-+ Boolean ow;
-+ AudioStreamBasicDescription d={0,};
-+ os=sizeof(d);
-+ AudioDeviceGetProperty(myDev,0,isinput,kAudioDevicePropertyStreamFormat,&os,&d);
-+ if (os > 0)
-+ {
-+ d.mSampleRate=srate;
-+ os=sizeof(d);
-+// AudioDeviceSetProperty(myDev,NULL,0,isinput,kAudioDevicePropertyStreamFormat,os,&d);
-+ AudioDeviceGetProperty(myDev,0,isinput,kAudioDevicePropertyStreamFormat,&os,&d);
-+ if (os>0) g_srate=m_srate=(int)d.mSampleRate;
-+ }
-+ AudioDeviceGetPropertyInfo(myDev,0,isinput,kAudioDevicePropertyStreamConfiguration,&os,&ow);
-+ if (os > 0)
-+ {
-+ AudioBufferList *buf=(AudioBufferList *)malloc(os);
-+ AudioDeviceGetProperty(myDev,0,isinput,kAudioDevicePropertyStreamConfiguration,&os,buf);
-+ int x;
-+ for (x = 0; x < (int)(os/sizeof(AudioBufferList)); x ++)
-+ {
-+ printf(" %s Channel %d: %d buffers\n",isinput?"Input":"Output",x,(int) buf[x].mNumberBuffers);
-+ int y;
-+ for (y = 0; y < (int)buf[x].mNumberBuffers; y++)
-+ {
-+ if (buf[x].mBuffers[y].mNumberChannels)
-+ printf(" buffer %d: %d channels\n",y,(int)buf[x].mBuffers[y].mNumberChannels);
-+ if (y == inchbuf && !x && buf[x].mBuffers[y].mNumberChannels)
-+ m_innch = buf[x].mBuffers[y].mNumberChannels;
-+ }
-+ break;
-+ }
-+
-+ free(buf);
-+ }
-+ if (os < sizeof(AudioBufferList))
-+ {
-+ printf("Device has no %s buffers! Invalid device?\n",isinput ? "Input" : "Output");
-+ return -1;
-+ }
-+ }
-+
-+ m_started=1;
-+ if (m_myDev_o != m_myDev_i)
-+ {
-+ AudioDeviceAddIOProc(m_myDev_i,caInproc,(void *)this);
-+ AudioDeviceAddIOProc(m_myDev_o,caOutproc,(void *)this);
-+
-+ AudioDeviceStart(m_myDev_i,caInproc);
-+ AudioDeviceStart(m_myDev_o,caOutproc);
-+ }
-+ else
-+ {
-+ AudioDeviceAddIOProc(m_myDev_i,caIOproc,(void *)this);
-+ AudioDeviceStart(m_myDev_i,caIOproc);
-+ }
-+
-+ return 0;
-+
-+}
-+
-+int audioStreamer_CoreAudio::Read(char *buf, int len) // returns 0 if blocked, < 0 if error, > 0 if data
-+{
-+ struct timespec s={0,1000*1000*10}; // sleep 10ms;
-+ nanosleep(&s,NULL);
-+// memset(buf,0,len);
-+ return 0;//len;
-+}
-+int audioStreamer_CoreAudio::Write(char *buf, int len) // returns 0 on success
-+{
-+ return 0;
-+}
-+
-+
-+audioStreamer *create_audioStreamer_CoreAudio(char **dev, int srate, int nch, int bps, SPLPROC proc)
-+{
-+ _splproc = proc;
-+ audioStreamer_CoreAudio *audio;
-+
-+ audio=new audioStreamer_CoreAudio;
-+
-+ if (audio->Open(dev,srate,nch,bps))
-+ {
-+ delete audio;
-+ return 0;
-+ }
-+ return audio;
-+}
-diff -Naur ninjam-cclient-0.01a/src/cursesclient/COMPILING ninjam/src/cursesclient/COMPILING
---- ninjam-cclient-0.01a/src/cursesclient/COMPILING 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/cursesclient/COMPILING 2005-08-30 22:07:40.000000000 +0000
-@@ -0,0 +1,19 @@
-+On linux, install libogg, libvorbis, libasound, then do
-+
-+make
-+
-+
-+and hope things work.
-+
-+On Mac OS X, once you have the dev tools installed, install libogg and
-+libvorbis, then do:
-+
-+export MAC=1
-+make
-+
-+
-+
-+good luck!
-+
-+-Justin
-+
-diff -Naur ninjam-cclient-0.01a/src/cursesclient/cursesclient.cpp ninjam/src/cursesclient/cursesclient.cpp
---- ninjam-cclient-0.01a/src/cursesclient/cursesclient.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/cursesclient/cursesclient.cpp 2006-01-09 18:46:57.000000000 +0000
-@@ -0,0 +1,1936 @@
-+/*
-+ NINJAM Curses Client - cursesclient.cpp
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ Curses (text mode) client code. On Windows this requires the (included)
-+ win32 curses emulation layer.
-+
-+ */
-+
-+#ifdef _WIN32
-+#define CURSES_INSTANCE (&m_cursinst)
-+#include <windows.h>
-+#include "curses.h"
-+#include "cursesclientinst.h"
-+#define strncasecmp strnicmp
-+#else
-+#include <stdlib.h>
-+#include <memory.h>
-+#include <curses.h>
-+#endif
-+
-+#include <stdio.h>
-+#include <ctype.h>
-+#include <math.h>
-+#include <signal.h>
-+#include <float.h>
-+
-+#include "../audiostream.h"
-+#include "../njclient.h"
-+#include "../../WDL/dirscan.h"
-+#include "../../WDL/lineparse.h"
-+
-+#include "../njmisc.h"
-+
-+
-+#define VALIDATE_TEXT_CHAR(thischar) ((isspace(thischar) || isgraph(thischar)) && (thischar) < 256)
-+#ifdef _WIN32
-+#define getch() curses_getch(CURSES_INSTANCE)
-+#define erase() curses_erase(CURSES_INSTANCE)
-+
-+void ninjamCursesClientInstance::Run()
-+{
-+}
-+
-+
-+ninjamCursesClientInstance m_cursinst;
-+
-+jesusonicAPI *JesusonicAPI;
-+WDL_String jesusdir;
-+#endif
-+
-+int g_chat_scroll=0;
-+int curs_ypos,curs_xpos;
-+int color_map[8];
-+int g_ui_inchat=0;
-+int g_done=0;
-+int g_ui_state=0;
-+int g_ui_locrename_ch;
-+int g_ui_voltweakstate_channel;
-+int g_need_disp_update;
-+char m_lineinput_str[120];
-+char m_chatinput_str[120];
-+
-+WDL_PtrList<char> g_chat_buffers;
-+
-+void addChatLine(char *src, char *text)
-+{
-+ while (g_chat_buffers.GetSize() > 256)
-+ {
-+ free(g_chat_buffers.Get(0));
-+ g_chat_buffers.Delete(0);
-+ }
-+ WDL_String tmp;
-+ if (src && *src && !strncmp(text,"/me ",4))
-+ {
-+ tmp.Set("* ");
-+ tmp.Append(src);
-+ tmp.Append(" ");
-+ char *p=text+3;
-+ while (*p == ' ') p++;
-+ tmp.Append(p);
-+ }
-+ else
-+ {
-+ if (src&&*src)
-+ {
-+ tmp.Set("<");
-+ tmp.Append(src);
-+ tmp.Append("> ");
-+ }
-+ else if (src)
-+ {
-+ tmp.Set("*** ");
-+ }
-+ tmp.Append(text);
-+ }
-+ g_chat_buffers.Add(strdup(tmp.Get()));
-+ g_chat_scroll=0;
-+}
-+
-+WDL_String g_topic;
-+
-+void chatmsg_cb(int user32, NJClient *inst, char **parms, int nparms)
-+{
-+ if (!parms[0]) return;
-+
-+ if (!strcmp(parms[0],"TOPIC"))
-+ {
-+ if (parms[2])
-+ {
-+ WDL_String tmp;
-+ if (parms[1] && *parms[1])
-+ {
-+ tmp.Set(parms[1]);
-+ tmp.Append(" sets topic to: ");
-+ }
-+ else tmp.Set("Topic is: ");
-+ tmp.Append(parms[2]);
-+
-+ g_topic.Set(parms[2]);
-+ addChatLine("",tmp.Get());
-+
-+ g_need_disp_update=1;
-+ }
-+ }
-+ else if (!strcmp(parms[0],"MSG"))
-+ {
-+ if (parms[1] && parms[2])
-+ addChatLine(parms[1],parms[2]);
-+ g_need_disp_update=1;
-+ }
-+ else if (!strcmp(parms[0],"PRIVMSG"))
-+ {
-+ if (parms[1] && parms[2])
-+ {
-+ WDL_String tmp;
-+ tmp.Set("*");
-+ tmp.Append(parms[1]);
-+ tmp.Append("* ");
-+ tmp.Append(parms[2]);
-+ addChatLine(NULL,tmp.Get());
-+ }
-+ g_need_disp_update=1;
-+ }
-+ else if (!strcmp(parms[0],"JOIN") || !strcmp(parms[0],"PART"))
-+ {
-+ if (parms[1] && *parms[1])
-+ {
-+ WDL_String tmp(parms[1]);
-+ tmp.Append(" has ");
-+ tmp.Append(parms[0][0]=='P' ? "left" : "joined");
-+ tmp.Append(" the server");
-+ addChatLine("",tmp.Get());
-+ }
-+ g_need_disp_update=1;
-+ }
-+}
-+
-+
-+#ifdef _WIN32
-+audioStreamer *CreateConfiguredStreamer(char *inifile, int showcfg, HWND hwndParent);
-+#endif
-+audioStreamer *g_audio;
-+NJClient *g_client;
-+
-+
-+void audiostream_onunder() { }
-+void audiostream_onover() { }
-+
-+int g_audio_enable=0;
-+
-+void audiostream_onsamples(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate)
-+{
-+ if (!g_audio_enable)
-+ {
-+ int x;
-+ // clear all output buffers
-+ for (x = 0; x < outnch; x ++) memset(outbuf[x],0,sizeof(float)*len);
-+ return;
-+ }
-+ g_client->AudioProc(inbuf,innch, outbuf, outnch, len,srate);
-+}
-+
-+
-+int g_sel_x, g_sel_ypos,g_sel_ycat;
-+
-+#define COLORMAP(x) color_map[x]
-+
-+
-+
-+// highlights shit in []
-+void highlightoutline(int line, char *str, int attrnorm, int bknorm, int attrhi, int bkhi, int attrsel, int bksel, int whl)
-+{
-+ int state=0;
-+ int l=COLS-1;
-+ int lcol=0;
-+ move(line,0);
-+ attrset(attrnorm);
-+ bkgdset(bknorm);
-+
-+ while (*str && l-- > 0)
-+ {
-+ if (*str == ']')
-+ {
-+ if (state)
-+ {
-+ attrset(attrnorm);
-+ bkgdset(bknorm);
-+ state=0;
-+ }
-+ }
-+ addch(*str);
-+ if (*str == '[')
-+ {
-+ if (whl > 0)
-+ {
-+ char *tmp=strstr(str,"]");
-+ if (tmp && !strstr(tmp,"["))
-+ {
-+ whl=0;
-+ g_sel_x=lcol;
-+ }
-+ }
-+ if (!state)
-+ {
-+ lcol++;
-+ if (!whl--)
-+ {
-+ attrset(attrsel);
-+ bkgdset(bksel);
-+ }
-+ else
-+ {
-+ attrset(attrhi);
-+ bkgdset(bkhi);
-+ }
-+ state=1;
-+ }
-+ }
-+ str++;
-+
-+ }
-+ if (state)
-+ {
-+ attrset(attrnorm);
-+ bkgdset(bknorm);
-+ }
-+
-+}
-+
-+
-+void drawstatusbar()
-+{
-+ if (g_ui_state) return;
-+ int l,p;
-+ g_client->GetPosition(&p,&l);
-+ if (!l) return;
-+
-+ bkgdset(COLORMAP(6));
-+ attrset(COLORMAP(6));
-+
-+ move(LINES-2,0);
-+ p*=(COLS);
-+ p/=l;
-+ int x;
-+ for (x = 0; x < COLS; x ++) addch(x <= p ? '#' : ' ');
-+
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+
-+ move(curs_ypos,curs_xpos);
-+}
-+
-+void showmainview(bool action=false, int ymove=0)
-+{
-+ int chat_lines=LINES/4;
-+ if (chat_lines<4) chat_lines=4;
-+
-+ int sec1lines=2;
-+ int x;
-+ for (x=0;x<MAX_LOCAL_CHANNELS;x++)
-+ {
-+ if (g_client->EnumLocalChannels(x)<0) break;
-+ sec1lines++;
-+ }
-+
-+ int sec2lines=0;
-+
-+ x=0;
-+ for (;;)
-+ {
-+ if (!g_client->GetUserState(x)) break;
-+
-+ int y=0;
-+ for (;;)
-+ {
-+ if (g_client->EnumUserChannels(x,y) < 0) break;
-+ sec2lines++;
-+ y++;
-+ }
-+ x++;
-+ }
-+ if (!sec2lines) sec2lines=1;
-+
-+ if (ymove < 0)
-+ {
-+ if (g_sel_ypos-- <= 0)
-+ {
-+ if (g_sel_ycat == 1) g_sel_ypos=sec1lines-1;
-+ else if (g_sel_ycat == 2) g_sel_ypos=sec2lines-1;
-+ else g_sel_ypos=0;
-+
-+ if (g_sel_ycat>0) g_sel_ycat--;
-+ }
-+ }
-+ else if (ymove > 0)
-+ {
-+ g_sel_ypos++;
-+ }
-+
-+ if (!ymove && g_sel_ycat == 1 && g_sel_ypos >= sec2lines)
-+ {
-+ g_sel_ypos=sec2lines-1;
-+ }
-+
-+ int selpos=0;
-+ int selcat=0;
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+
-+ erase();
-+ bkgdset(COLORMAP(1));
-+ attrset(COLORMAP(1));
-+ mvaddstr(0,0,"LOCAL");
-+ clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+ char linebuf[1024];
-+ int linemax=LINES-2-chat_lines;
-+ {
-+ if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-+ {
-+ if (g_sel_x == 1 || g_sel_x == 3)
-+ {
-+ g_ui_state=1;
-+ g_ui_voltweakstate_channel=g_sel_x == 1 ? -2 : -1;
-+ }
-+ else
-+ {
-+ if (g_sel_x == 0)
-+ {
-+ g_client->config_mastermute=!g_client->config_mastermute;
-+ }
-+ else
-+ {
-+ g_client->config_metronome_mute=!g_client->config_metronome_mute;
-+ }
-+ }
-+ }
-+ sprintf(linebuf," master: [%c]mute [",g_client->config_mastermute?'X':' ');
-+ mkvolpanstr(linebuf+strlen(linebuf),g_client->config_mastervolume,g_client->config_masterpan);
-+
-+ sprintf(linebuf+strlen(linebuf),"] | metronome: [%c]mute [",g_client->config_metronome_mute?'X':' ');
-+ mkvolpanstr(linebuf+strlen(linebuf),g_client->config_metronome,g_client->config_metronome_pan);
-+ sprintf(linebuf+strlen(linebuf),"]");
-+
-+ highlightoutline(1,linebuf,COLORMAP(0),COLORMAP(0),
-+ COLORMAP(0)|A_BOLD,COLORMAP(0),
-+ COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-+// mvaddnstr(1,0,linebuf,COLS-1);
-+ }
-+ int ypos=2;
-+ for (x=0;ypos < linemax;x++)
-+ {
-+ int a=g_client->EnumLocalChannels(x);
-+ if (a<0) break;
-+ int sch;
-+ bool bc,mute;
-+ float vol,pan;
-+ char *name=g_client->GetLocalChannelInfo(a,&sch,NULL,&bc);
-+ g_client->GetLocalChannelMonitoring(a,&vol,&pan,&mute,NULL);
-+
-+ if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-+ {
-+ if (g_sel_x == 0)
-+ {
-+ g_ui_state=2;
-+ g_ui_locrename_ch=a;
-+ strncpy(m_lineinput_str,name,sizeof(m_lineinput_str)-1);
-+ }
-+ else if (g_sel_x == 1)
-+ {
-+ // toggle active
-+ g_client->SetLocalChannelInfo(a,NULL,false,0,false,0,true,bc=!bc);
-+ g_client->NotifyServerOfChannelChange();
-+ }
-+ else if (g_sel_x == 2)
-+ {
-+ g_ui_state=3;
-+ g_ui_locrename_ch=a;
-+ }
-+ else if (g_sel_x == 3)
-+ {
-+ // mute
-+ g_client->SetLocalChannelMonitoring(a,false,0.0f,false,0.0f,true,mute=!mute,false,false);
-+ }
-+ else if (g_sel_x == 4)
-+ {
-+ //volume
-+ g_ui_state=1;
-+ g_ui_voltweakstate_channel=a;
-+ }
-+#ifdef _WIN32
-+ else if (g_sel_x >= 6 && JesusonicAPI)
-+ {
-+ void *i=0;
-+ g_client->GetLocalChannelProcessor(a,NULL,&i);
-+ if (!i)
-+ {
-+ // start it up
-+ void *p=CreateJesusInstance(a,"",g_audio->m_srate);
-+ if (p) g_client->SetLocalChannelProcessor(a,jesusonic_processor,p);
-+ }
-+ else
-+ {
-+ if (g_sel_x >= 7) // kill
-+ {
-+ g_client->SetLocalChannelProcessor(a,NULL,NULL);
-+ deleteJesusonicProc(i,a);
-+ }
-+ else
-+ {
-+ // JesusonicAPI->ui_wnd_destroy(i);
-+ HWND h=JesusonicAPI->ui_wnd_gethwnd(i);
-+ if (h && IsWindow(h))
-+ {
-+ ShowWindow(h,SW_SHOWNA);
-+ SetForegroundWindow(h);
-+ }
-+ else
-+ {
-+ HWND h=JesusonicAPI->ui_wnd_create(i);
-+ ShowWindow(h,SW_SHOWNA);
-+ SetTimer(h,1,40,NULL);
-+ SetForegroundWindow(h);
-+ }
-+
-+ // show
-+ }
-+ }
-+ }
-+#endif
-+ else if (g_sel_x >= 5)
-+ {
-+#ifdef _WIN32
-+ void *i=0;
-+ g_client->GetLocalChannelProcessor(a,NULL,&i);
-+ if (i) deleteJesusonicProc(i,a);
-+#endif
-+ g_client->DeleteLocalChannel(a);
-+ g_client->NotifyServerOfChannelChange();
-+ x--;
-+ action=0;
-+ continue;
-+ // delete
-+ }
-+ }
-+
-+
-+#ifdef _WIN32
-+ void *tmp;
-+ g_client->GetLocalChannelProcessor(a,NULL,&tmp);
-+#endif
-+ char volstr[256];
-+ mkvolpanstr(volstr,vol,pan);
-+ const char *sname=g_audio->GetChannelName(sch);
-+ if (!sname) sname="Silence";
-+
-+ char snamebuf[32];
-+ if (strlen(sname)>16)
-+ {
-+ strcpy(snamebuf,"...");
-+ strcat(snamebuf,sname+strlen(sname)-13);
-+ sname=snamebuf;
-+ }
-+ sprintf(linebuf," [%s] [%c]xmit [%s] [%c]mute [%s] [del] ",name,bc?'X':' ',sname,mute?'X':' ',volstr);
-+
-+
-+#ifdef _WIN32
-+ if (JesusonicAPI)
-+ {
-+ sprintf(linebuf+strlen(linebuf),"[js][%c] ", tmp?'x': ' ');
-+ }
-+#endif
-+
-+ sprintf(linebuf+strlen(linebuf),
-+ "<%2.1fdB>",
-+ VAL2DB(g_client->GetLocalChannelPeak(a)));
-+
-+ highlightoutline(ypos++,linebuf,COLORMAP(0),COLORMAP(0),
-+ COLORMAP(0)|A_BOLD,COLORMAP(0),
-+ COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-+ }
-+ if (ypos < LINES-3)
-+ {
-+ if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-+ {
-+ int x;
-+ for (x = 0; x < g_client->GetMaxLocalChannels(); x ++)
-+ {
-+ if (!g_client->GetLocalChannelInfo(x,NULL,NULL,NULL)) break;
-+ }
-+ if (x < g_client->GetMaxLocalChannels())
-+ {
-+ g_client->SetLocalChannelInfo(x,"channel",true,0,false,0,true,false);
-+ g_client->NotifyServerOfChannelChange();
-+
-+ const char *sname=g_audio->GetChannelName(0);
-+ if (!sname) sname="Silence";
-+
-+ char snamebuf[32];
-+ if (strlen(sname)>16)
-+ {
-+ strcpy(snamebuf,"...");
-+ strcat(snamebuf,sname+strlen(sname)-13);
-+ sname=snamebuf;
-+ }
-+
-+ char volstr[256];
-+ mkvolpanstr(volstr,1.0f,0.0f);
-+ sprintf(linebuf," [channel] [ ]xmit [%s] [ ]mute [%s] [del] %s<-120dB>",
-+ sname,
-+ volstr,
-+#ifdef _WIN32
-+ JesusonicAPI?"[js][ ] " :
-+#endif
-+ ""
-+
-+ );
-+
-+ action=false;
-+ selpos++;
-+
-+ highlightoutline(ypos++,linebuf,COLORMAP(0),COLORMAP(0),
-+ COLORMAP(0)|A_BOLD,COLORMAP(0),
-+ COLORMAP(5),COLORMAP(5),g_sel_x);
-+
-+ }
-+ }
-+ if (ypos < LINES-3)
-+ {
-+ highlightoutline(ypos++," [new channel]",COLORMAP(0),COLORMAP(0),
-+ COLORMAP(0)|A_BOLD,COLORMAP(0),
-+ COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-+ }
-+ }
-+
-+ int wasadv=0;
-+ if (g_sel_ycat == selcat && g_sel_ypos >= selpos)
-+ {
-+ wasadv=1;
-+ g_sel_ycat++;
-+ g_sel_ypos=0;
-+ }
-+
-+ selpos=0;
-+ selcat=1;
-+
-+ if (ypos < LINES-3)
-+ {
-+ bkgdset(COLORMAP(6));
-+ attrset(COLORMAP(6));
-+ mvaddnstr(ypos++,0,"REMOTE",COLS-1);
-+ clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+ }
-+ int user=0;
-+ x=0;
-+ while (ypos < linemax)
-+ {
-+ if (!x) // show user info
-+ {
-+ char *name=g_client->GetUserState(user);
-+ if (!name) break;
-+
-+ bkgdset(COLORMAP(4));
-+ attrset(COLORMAP(4));
-+ mvaddnstr(ypos++,0,name,COLS-1);
-+
-+ clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+
-+ }
-+
-+ if (ypos >= linemax) break;
-+
-+ int a=g_client->EnumUserChannels(user,x);
-+ if (a < 0)
-+ {
-+ x=0;
-+ user++;
-+ continue;
-+ }
-+
-+ float vol,pan;
-+ bool sub,mute;
-+ char *name=g_client->GetUserChannelState(user,a,&sub,&vol,&pan,&mute);
-+ // show channel info
-+
-+
-+ if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-+ {
-+ if (g_sel_x == 0)
-+ {
-+ // toggle subscribe
-+ g_client->SetUserChannelState(user,a,true,sub=!sub,false,0.0f,false,0.0f,false,false,false,false);
-+ }
-+ else if (g_sel_x == 1)
-+ {
-+ // toggle mute
-+ g_client->SetUserChannelState(user,a,false,false,false,0.0f,false,0.0f,true,mute=!mute,false,false);
-+ }
-+ else if (g_sel_x >= 2)
-+ {
-+ // volume
-+ g_ui_state=1;
-+ g_ui_voltweakstate_channel=1024+64*user+a;
-+ }
-+ }
-+
-+ char volstr[256];
-+ mkvolpanstr(volstr,vol,pan);
-+ sprintf(linebuf," \"%s\" [%c]recv [%c]mute [%s] <%2.1fdB>",name,sub?'X':' ',mute?'X':' ',volstr,VAL2DB(g_client->GetUserChannelPeak(user,a)));
-+
-+ highlightoutline(ypos++,linebuf,COLORMAP(0),COLORMAP(0),
-+ COLORMAP(0)|A_BOLD,COLORMAP(0),
-+ COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-+
-+ x++;
-+
-+
-+ }
-+
-+ if (!selpos && ypos < linemax)
-+ {
-+ highlightoutline(ypos++,"[no remote users]",COLORMAP(0),COLORMAP(0),
-+ COLORMAP(0)|A_BOLD,COLORMAP(0),
-+ COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos++ || g_sel_ycat != selcat) ? -1 : g_sel_x);
-+ }
-+
-+ curs_ypos=LINES-1;
-+ curs_xpos=0;
-+
-+ if (!selpos && wasadv) g_sel_ycat++;
-+ if (selpos > 0 && g_sel_ycat == selcat && g_sel_ypos >= selpos)
-+ {
-+ g_sel_ycat++;
-+ g_sel_ypos=0;
-+ }
-+
-+ selcat=2;
-+ selpos=0;
-+
-+ g_ui_inchat=0;
-+ if (chat_lines>=4)
-+ {
-+ bkgdset(COLORMAP(1));
-+ attrset(COLORMAP(1));
-+ mvaddnstr(LINES-2-chat_lines,0,g_topic.Get()[0]?g_topic.Get():"CHAT",COLS-1);
-+ clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+
-+ int x;
-+ if (g_chat_scroll > g_chat_buffers.GetSize()-(chat_lines-2)) g_chat_scroll=g_chat_buffers.GetSize()-(chat_lines-2);
-+ int pos=g_chat_buffers.GetSize()-g_chat_scroll;
-+ if (pos < 0) pos=0;
-+ else if (pos > g_chat_buffers.GetSize()) pos=g_chat_buffers.GetSize();
-+
-+ for (x = 0; x < chat_lines-2; )
-+ {
-+ char *p;
-+ if (--pos < 0 || !(p=g_chat_buffers.Get(pos))) break;
-+
-+ char *np=p;
-+ int maxw=COLS-1;
-+ while ((int)strlen(np) > maxw) np+=maxw;
-+
-+ while (np >= p && x < chat_lines-2)
-+ {
-+ mvaddnstr(LINES-2-2-x,0,np,maxw);
-+ x++;
-+ np-=maxw;
-+ }
-+
-+ }
-+
-+ if (g_sel_ycat == selcat && g_sel_ypos == selpos++)
-+ {
-+ g_sel_x=0;
-+ g_ui_inchat=1;
-+ bkgdset(COLORMAP(2));
-+ attrset(COLORMAP(2));
-+ curs_ypos=LINES-2-1;
-+ curs_xpos=strlen(m_chatinput_str);
-+ }
-+ else
-+ {
-+ bkgdset(COLORMAP(3));
-+ attrset(COLORMAP(3));
-+ }
-+ mvaddstr(LINES-2-1,0,m_chatinput_str);
-+ clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+ }
-+
-+
-+ if (g_sel_ycat == selcat && g_sel_ypos > selpos) g_sel_ypos=selpos;
-+
-+ if (g_ui_state==1)
-+ {
-+ bkgdset(COLORMAP(2));
-+ attrset(COLORMAP(2));
-+ mvaddnstr(LINES-2,0,"USE UP AND DOWN FOR VOLUME, LEFT AND RIGHT FOR PANNING, ENTER WHEN DONE",COLS-1);
-+ clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+ }
-+ else if (g_ui_state == 3)
-+ {
-+ bkgdset(COLORMAP(2));
-+ attrset(COLORMAP(2));
-+ mvaddnstr(LINES-2,0,"USE ARROW KEYS TO SELECT THE INPUT CHANNEL, ENTER WHEN DONE",COLS-1);
-+ clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+ }
-+ else drawstatusbar();
-+
-+
-+ ypos=LINES-1;
-+ sprintf(linebuf,"[QUIT NINJAM] : %s : %.1fBPM %dBPI : %dHz %dch->%dch %dbps%s",
-+ g_client->GetHostName(),g_client->GetActualBPM(),g_client->GetBPI(),g_audio->m_srate,g_audio->m_innch,g_audio->m_outnch,g_audio->m_bps&~7,g_audio->m_bps&1 ? "(f)":"");
-+ highlightoutline(ypos++,linebuf,COLORMAP(1),COLORMAP(1),COLORMAP(1),COLORMAP(1),COLORMAP(5),COLORMAP(5),(g_sel_ypos != selpos || g_sel_ycat != selcat) ? -1 : g_sel_x);
-+ attrset(COLORMAP(1));
-+ bkgdset(COLORMAP(1));
-+ clrtoeol();
-+ if (action && g_sel_ycat == selcat && g_sel_ypos == selpos)
-+ {
-+ g_done++;
-+ }
-+
-+ if (g_ui_state == 2 || g_ui_state == 4)
-+ {
-+ bkgdset(COLORMAP(2));
-+ attrset(COLORMAP(2));
-+ char *p1="RENAME CHANNEL:";
-+ mvaddnstr(LINES-2,0,p1,COLS-1);
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+
-+ if ((int)strlen(p1) < COLS-2) { addch(' '); addnstr(m_lineinput_str,COLS-2-strlen(p1)); }
-+
-+ clrtoeol();
-+ }
-+ else
-+ {
-+ move(curs_ypos,curs_xpos);
-+ }
-+
-+}
-+
-+
-+
-+
-+void sigfunc(int sig)
-+{
-+ printf("Got Ctrl+C\n");
-+ g_done++;
-+}
-+
-+
-+void usage(int noexit=0)
-+{
-+
-+ printf("Usage: NINJAM hostname [options]\n"
-+ "Options:\n"
-+ " -user <username>\n"
-+ " -pass <password>\n"
-+#ifdef _WIN32
-+ " -noaudiocfg\n"
-+ " -jesusonic <path to jesusonic root dir>\n"
-+#else
-+#ifdef _MAC
-+ " -audiostr device_name[,output_device_name]\n"
-+#else
-+ " -audiostr \"option value [option value ...]\"\n"
-+ " ALSA audio options are:\n"
-+ " in hw:0,0 -- set input device\n"
-+ " out hw:0,0 -- set output device\n"
-+ " srate 48000 -- set samplerate\n"
-+ " nch 2 -- set channels\n"
-+ " bps 16 -- set bits/sample\n"
-+ " bsize 2048 -- set blocksize (bytes)\n"
-+ " nblock 16 -- set number of blocks\n"
-+#endif
-+#endif
-+
-+ " -sessiondir <path> -- sets the session directory (default: auto)\n"
-+ " -savelocalwavs -- save full quality copies of recorded files\n"
-+ " -nosavesourcefiles -- don't save source files for remixing\n"
-+
-+ " -writewav -- writes a .wav of the jam in the session directory\n"
-+ " -writeogg <bitrate> -- writes a .ogg of the jam (bitrate 64-256)..\n");
-+
-+ if (!noexit) exit(1);
-+}
-+
-+int licensecallback(int user32, char *licensetext)
-+{
-+ /* todo, curses shit */
-+
-+ int isscrolled=0;
-+ int linepos=0;
-+ int needref=1;
-+ int retval=0;
-+ while (!retval)
-+ {
-+ if (needref)
-+ {
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+
-+ erase();
-+ char *tp=licensetext;
-+ needref=0;
-+ bkgdset(COLORMAP(6));
-+ attrset(COLORMAP(6));
-+ mvaddnstr(0,0,"You must agree to this license by scrolling down",COLS-1); clrtoeol();
-+ mvaddnstr(1,0,"and hitting Y to connect to this server:",COLS-1); clrtoeol();
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+
-+ int x;
-+ for (x = 0; x < linepos; x ++)
-+ {
-+ int yp=0;
-+ while (*tp && *tp != '\n' && x < linepos)
-+ {
-+ if (yp++ >= COLS-1)
-+ {
-+ x++;
-+ yp=0;
-+ }
-+ tp++;
-+ }
-+ if (*tp) tp++;
-+ }
-+ for (x = 2; x < LINES-1 && *tp; x ++)
-+ {
-+ move(x,0);
-+ int yp=0;
-+ while (*tp && *tp != '\n' && x < LINES-1)
-+ {
-+ if (yp++ >= COLS-1)
-+ {
-+ x++;
-+ yp=0;
-+ move(x,0);
-+ }
-+ addch(*tp);
-+ tp++;
-+ }
-+ if (*tp) tp++;
-+ }
-+ bkgdset(COLORMAP(5));
-+ attrset(COLORMAP(5));
-+
-+ if (*tp)
-+ {
-+ mvaddstr(LINES-1,0,"Use the arrows or pagedown to scroll down");
-+ clrtoeol();
-+ isscrolled=0;
-+ }
-+ else
-+ {
-+ mvaddstr(LINES-1,0,"Hit Y to agree");
-+ clrtoeol();
-+ isscrolled=1;
-+ }
-+ bkgdset(COLORMAP(0));
-+ attrset(COLORMAP(0));
-+ }
-+
-+ int a=getch();
-+ switch (a)
-+ {
-+ case KEY_UP:
-+ case KEY_PPAGE:
-+ needref=1;
-+ linepos -= a == KEY_UP ? 1 : 10;
-+ if (linepos <0) linepos=0;
-+ break;
-+ case KEY_DOWN:
-+ case KEY_NPAGE:
-+ if (!isscrolled) linepos += a == KEY_DOWN ? 1 : 10;
-+ needref=1;
-+ break;
-+ case 'y':
-+ case 'Y':
-+ if (isscrolled) retval=1;
-+ break;
-+ case 27:
-+ retval=-1;
-+ break;
-+ };
-+
-+
-+#ifdef _WIN32
-+ MSG msg;
-+ while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
-+ {
-+ TranslateMessage(&msg);
-+ DispatchMessage(&msg);
-+ }
-+ Sleep(1);
-+#else
-+ struct timespec ts={0,1000*1000};
-+ nanosleep(&ts,NULL);
-+#endif
-+
-+ }
-+
-+ showmainview();
-+ return retval>0;
-+}
-+
-+int main(int argc, char **argv)
-+{
-+ char *parmuser=NULL;
-+ char *parmpass=NULL;
-+ WDL_String sessiondir;
-+ int sessionspec=0;
-+ int nolog=0,nowav=1,writeogg=0,g_nssf=0;
-+
-+ printf("NINJAM v0.01a ALPHA curses client, compiled " __DATE__ " at " __TIME__ "\nCopyright (C) 2004-2005 Cockos, Inc.\n\n");
-+ char *audioconfigstr=NULL;
-+ g_client=new NJClient;
-+ g_client->config_savelocalaudio=1;
-+ g_client->LicenseAgreementCallback=licensecallback;
-+ g_client->ChatMessage_Callback=chatmsg_cb;
-+
-+ char *hostname;
-+
-+#if 1//def _MAC
-+ char hostbuf[512];
-+ if (argc < 2)
-+ {
-+ usage(1);
-+ printf("(no command line options specified, using interactive mode!)\n\n\nHost to connect to: ");
-+ fgets(hostbuf,sizeof(hostbuf),stdin);
-+ if (hostbuf[0] && hostbuf[strlen(hostbuf)-1] == '\n') hostbuf[strlen(hostbuf)-1]=0;
-+ hostname=hostbuf;
-+ if (!hostbuf[0]) return 0;
-+ }
-+#else
-+ if (argc < 2) usage();
-+#endif
-+ else hostname=argv[1];
-+
-+
-+
-+
-+ {
-+ int p;
-+ for (p = 2; p < argc; p++)
-+ {
-+ if (!stricmp(argv[p],"-savelocalwavs"))
-+ {
-+ g_client->config_savelocalaudio=2;
-+ }
-+ else if (!stricmp(argv[p],"-nosavelocal"))
-+ {
-+ g_client->config_savelocalaudio=0;
-+ }
-+ else if (!stricmp(argv[p],"-debuglevel"))
-+ {
-+ if (++p >= argc) usage();
-+ g_client->config_debug_level=atoi(argv[p]);
-+ }
-+ else if (!stricmp(argv[p],"-noaudiocfg"))
-+ {
-+ audioconfigstr="";
-+ }
-+ else if (!stricmp(argv[p],"-audiostr"))
-+ {
-+ if (++p >= argc) usage();
-+ audioconfigstr=argv[p];
-+ }
-+ else if (!stricmp(argv[p],"-user"))
-+ {
-+ if (++p >= argc) usage();
-+ parmuser=argv[p];
-+ }
-+ else if (!stricmp(argv[p],"-pass"))
-+ {
-+ if (++p >= argc) usage();
-+ parmpass=argv[p];
-+ }
-+ else if (!stricmp(argv[p],"-writewav"))
-+ {
-+ nowav=0;
-+ }
-+ else if (!stricmp(argv[p],"-writeogg"))
-+ {
-+ if (++p >= argc) usage();
-+ writeogg=atoi(argv[p]);
-+ }
-+ else if (!stricmp(argv[p],"-nowritelog"))
-+ {
-+ nolog++;
-+ }
-+ else if (!stricmp(argv[p],"-nosavesourcefiles"))
-+ {
-+ g_nssf++;
-+ }
-+#ifdef _WIN32
-+ else if (!stricmp(argv[p],"-jesusonic"))
-+ {
-+ if (++p >= argc) usage();
-+ jesusdir.Set(argv[p]);
-+ }
-+#endif
-+ else if (!stricmp(argv[p],"-sessiondir"))
-+ {
-+ if (++p >= argc) usage();
-+ sessiondir.Set(argv[p]);
-+ sessionspec=1;
-+ }
-+ else usage();
-+ }
-+ }
-+
-+ if (g_nssf)
-+ {
-+ g_client->config_savelocalaudio=0;
-+ nolog++;
-+ }
-+
-+ char passbuf[512]="";
-+ char userbuf[512]="";
-+ if (!parmuser)
-+ {
-+ parmuser=userbuf;
-+ printf("Enter username: ");
-+ fgets(userbuf,sizeof(userbuf),stdin);
-+ if (userbuf[0] && userbuf[strlen(userbuf)-1] == '\n') userbuf[strlen(userbuf)-1]=0;
-+ if (!userbuf[0]) return 0;
-+ }
-+ if (!parmpass)
-+ {
-+ parmpass=passbuf;
-+ if (strncmp(parmuser,"anonymous",9) || (parmuser[9] && parmuser[9] != ':'))
-+ {
-+ printf("Enter password: ");
-+ fgets(passbuf,sizeof(passbuf),stdin);
-+ if (passbuf[0] && passbuf[strlen(passbuf)-1] == '\n') passbuf[strlen(passbuf)-1]=0;
-+ }
-+ }
-+
-+#ifdef _WIN32
-+ g_audio=CreateConfiguredStreamer("ninjam.ini", !audioconfigstr, NULL);
-+
-+#else
-+ {
-+ char *dev_name_in=audioconfigstr;
-+#ifdef _MAC
-+ g_audio=create_audioStreamer_CoreAudio(&dev_name_in,48000,2,16,audiostream_onsamples);
-+#else
-+ g_audio=create_audioStreamer_JACK(dev_name_in,audiostream_onsamples);
-+#endif
-+ }
-+#endif
-+ if (!g_audio)
-+ {
-+ printf("Error opening audio!\n");
-+ return 0;
-+ }
-+ printf("Opened at %dHz %d->%dch %dbps\n",
-+ g_audio->m_srate, g_audio->m_innch, g_audio->m_outnch, g_audio->m_bps);
-+
-+ signal(SIGINT,sigfunc);
-+
-+ JNL::open_socketlib();
-+
-+
-+ // jesusonic init
-+
-+#ifdef _WIN32
-+ HINSTANCE jesus_hDllInst;
-+ WDL_String jesusonic_configfile;
-+ if (jesusdir.Get()[0])
-+ {
-+ jesusonic_configfile.Set(jesusdir.Get());
-+ jesusonic_configfile.Append("\\cmdclient.jesusonicpreset");
-+ WDL_String dll;
-+ dll.Set(jesusdir.Get());
-+ dll.Append("\\jesus.dll");
-+
-+ jesus_hDllInst = LoadLibrary(".\\jesus.dll"); // load from current dir
-+ if (!jesus_hDllInst) jesus_hDllInst = LoadLibrary(dll.Get());
-+ if (jesus_hDllInst)
-+ {
-+ *(void **)(&JesusonicAPI) = (void *)GetProcAddress(jesus_hDllInst,"JesusonicAPI");
-+ if (JesusonicAPI && JesusonicAPI->ver == JESUSONIC_API_VERSION_CURRENT)
-+ {
-+ }
-+ else JesusonicAPI = 0;
-+ }
-+ }
-+
-+#endif
-+ // end jesusonic init
-+
-+ {
-+ FILE *fp=fopen("ninjam.config","rt");
-+ int x=0;
-+ if (fp)
-+ {
-+ bool comment_state=false;
-+ while (!feof(fp))
-+ {
-+ char buf[4096];
-+ buf[0]=0;
-+ fgets(buf,sizeof(buf),fp);
-+ if (!buf[0]) continue;
-+ if (buf[strlen(buf)-1] == '\n')
-+ buf[strlen(buf)-1]=0;
-+ if (!buf[0]) continue;
-+
-+ LineParser lp(comment_state);
-+
-+ lp.parse(buf);
-+
-+ switch (lp.gettoken_enum(0,"local\0master\0"))
-+ {
-+ case 0:
-+ // process local line
-+ if (lp.getnumtokens()>2)
-+ {
-+ int ch=lp.gettoken_int(1);
-+ int n;
-+ for (n = 2; n < lp.getnumtokens()-1; n += 2)
-+ {
-+ switch (lp.gettoken_enum(n,"source\0bc\0mute\0solo\0volume\0pan\0jesus\0name\0"))
-+ {
-+ case 0: // source
-+ g_client->SetLocalChannelInfo(ch,NULL,true,lp.gettoken_int(n+1),false,0,false,false);
-+ break;
-+ case 1: //broadcast
-+ g_client->SetLocalChannelInfo(ch,NULL,false,false,false,0,true,!!lp.gettoken_int(n+1));
-+ break;
-+ case 2: //mute
-+ g_client->SetLocalChannelMonitoring(ch,false,false,false,false,true,!!lp.gettoken_int(n+1),false,false);
-+ break;
-+ case 3: //solo
-+ g_client->SetLocalChannelMonitoring(ch,false,false,false,false,false,false,true,!!lp.gettoken_int(n+1));
-+ break;
-+ case 4: //volume
-+ g_client->SetLocalChannelMonitoring(ch,true,(float)lp.gettoken_float(n+1),false,false,false,false,false,false);
-+ break;
-+ case 5: //pan
-+ g_client->SetLocalChannelMonitoring(ch,false,false,true,(float)lp.gettoken_float(n+1),false,false,false,false);
-+ break;
-+ case 6: //jesus
-+ if (lp.gettoken_int(n+1))
-+ {
-+#ifdef _WIN32
-+ void *p=CreateJesusInstance(ch,"",g_audio->m_srate);
-+ if (p) g_client->SetLocalChannelProcessor(ch,jesusonic_processor,p);
-+#endif
-+ }
-+ break;
-+ case 7: //name
-+ g_client->SetLocalChannelInfo(ch,lp.gettoken_str(n+1),false,false,false,0,false,false);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+ }
-+
-+ break;
-+ case 1:
-+ if (lp.getnumtokens()>2)
-+ {
-+ int n;
-+ for (n = 1; n < lp.getnumtokens()-1; n += 2)
-+ {
-+ switch (lp.gettoken_enum(n,"mastervol\0masterpan\0metrovol\0metropan\0mastermute\0metromute\0"))
-+ {
-+ case 0: // mastervol
-+ g_client->config_mastervolume = (float)lp.gettoken_float(n+1);
-+ break;
-+ case 1: // masterpan
-+ g_client->config_masterpan = (float)lp.gettoken_float(n+1);
-+ break;
-+ case 2:
-+ g_client->config_metronome = (float)lp.gettoken_float(n+1);
-+ break;
-+ case 3:
-+ g_client->config_metronome_pan = (float)lp.gettoken_float(n+1);
-+ break;
-+ case 4:
-+ g_client->config_mastermute = !!lp.gettoken_int(n+1);
-+ break;
-+ case 5:
-+ g_client->config_metronome_mute = !!lp.gettoken_int(n+1);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+
-+
-+ }
-+ fclose(fp);
-+ }
-+ else // set up defaults
-+ {
-+ g_client->SetLocalChannelInfo(0,"channel0",true,0,false,0,true,true);
-+ g_client->SetLocalChannelMonitoring(0,false,0.0f,false,0.0f,false,false,false,false);
-+ }
-+ }
-+
-+ if (!sessiondir.Get()[0])
-+ {
-+ char buf[512];
-+
-+ int cnt=0;
-+ while (cnt < 16)
-+ {
-+#if 0 // _WIN32
-+ SYSTEMTIME st;
-+ GetLocalTime(&st);
-+ wsprintf(buf,"%04d%02d%02d_%02d%02d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute);
-+#else
-+ time_t tv;
-+ time(&tv);
-+ struct tm *t=localtime(&tv);
-+ sprintf(buf,"%04d%02d%02d_%02d%02d",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min);
-+#endif
-+ if (cnt)
-+ wsprintf(buf+strlen(buf),"_%d",cnt);
-+ strcat(buf,".ninjam");
-+
-+#ifdef _WIN32
-+ if (CreateDirectory(buf,NULL)) break;
-+#else
-+ if (!mkdir(buf,0700)) break;
-+#endif
-+
-+ cnt++;
-+ }
-+
-+ if (cnt >= 16)
-+ {
-+ printf("Error creating session directory\n");
-+ buf[0]=0;
-+ return 0;
-+ }
-+
-+ sessiondir.Set(buf);
-+ }
-+ else
-+#ifdef _WIN32
-+ CreateDirectory(sessiondir.Get(),NULL);
-+#else
-+ mkdir(sessiondir.Get(),0700);
-+#endif
-+ if (sessiondir.Get()[0] && sessiondir.Get()[strlen(sessiondir.Get())-1]!='\\' && sessiondir.Get()[strlen(sessiondir.Get())-1]!='/')
-+#ifdef _WIN32
-+ sessiondir.Append("\\");
-+#else
-+ sessiondir.Append("/");
-+#endif
-+
-+ g_client->SetWorkDir(sessiondir.Get());
-+
-+
-+ if (!nowav)
-+ {
-+ WDL_String wf;
-+ wf.Set(sessiondir.Get());
-+ wf.Append("output.wav");
-+ g_client->waveWrite = new WaveWriter(wf.Get(),24,g_audio->m_outnch>1?2:1,g_audio->m_srate);
-+ }
-+ if (writeogg)
-+ {
-+ WDL_String wf;
-+ wf.Set(sessiondir.Get());
-+ wf.Append("output.ogg");
-+ g_client->SetOggOutFile(fopen(wf.Get(),"ab"),g_audio->m_srate,g_audio->m_outnch>1?2:1,writeogg);
-+ }
-+ if (!nolog)
-+ {
-+ WDL_String lf;
-+ lf.Set(sessiondir.Get());
-+ lf.Append("clipsort.log");
-+ g_client->SetLogFile(lf.Get());
-+ }
-+
-+ printf("Connecting to %s...\n",hostname);
-+ g_client->Connect(hostname,parmuser,parmpass);
-+ g_audio_enable=1;
-+
-+
-+
-+ // go into leet curses mode now
-+#ifdef _WIN32
-+ initscr(0);
-+#else
-+ initscr();
-+#endif
-+ cbreak();
-+ noecho();
-+ nonl();
-+ intrflush(stdscr,FALSE);
-+ keypad(stdscr,TRUE);
-+ nodelay(stdscr,TRUE);
-+ raw(); // disable ctrl+C etc. no way to kill if allow quit isn't defined, yay.
-+
-+#ifndef _WIN32
-+ ESCDELAY=0; // dont wait--at least on the console this seems to work.
-+#endif
-+
-+ if (has_colors()) // we don't use color yet, but we could
-+ {
-+ start_color();
-+ init_pair(1, COLOR_WHITE, COLOR_BLUE); // normal status lines
-+ init_pair(2, COLOR_BLACK, COLOR_CYAN); // value
-+
-+#ifdef COLOR_BLUE_DIM
-+ init_pair(3, COLOR_WHITE, COLOR_BLUE_DIM); // alternating shit for the effect view
-+ init_pair(4, COLOR_WHITE, COLOR_RED_DIM);
-+#else
-+
-+#if 0 // ok this aint gonna do shit for us :(
-+ if (can_change_color() && init_color(COLOR_YELLOW,0,0,150) && init_color(COLOR_MAGENTA,150,0,0))
-+ {
-+ init_pair(3, COLOR_WHITE, COLOR_YELLOW); // alternating shit for the effect view
-+ init_pair(4, COLOR_WHITE, COLOR_MAGENTA);
-+ }
-+ else
-+#endif
-+
-+
-+#ifdef VGA_CONSOLE
-+ char *term=getenv("TERM");
-+ if (term && !strcmp(term,"linux") && !ioperm(0x3C8,2,1))
-+ {
-+ init_pair(3, COLOR_WHITE, COLOR_YELLOW); // alternating shit for the effect view
-+ init_pair(4, COLOR_WHITE, COLOR_MAGENTA);
-+ set_pal(6,0,0,15);
-+ set_pal(5,15,0,0);
-+ }
-+ else
-+#endif
-+ {
-+ init_pair(3, COLOR_WHITE, COLOR_BLUE); // alternating shit for the effect view
-+ init_pair(4, COLOR_WHITE, COLOR_RED);
-+ }
-+#endif
-+ init_pair(5, COLOR_BLACK, COLOR_WHITE);
-+ init_pair(6, COLOR_WHITE, COLOR_RED);
-+ int x;
-+ for (x = 1; x < 8; x ++)
-+ color_map[x]=COLOR_PAIR(x);
-+
-+ }
-+#ifndef _WIN32
-+ else
-+ {
-+// color_map[1]=A_BOLD;
-+ color_map[2]=A_STANDOUT;
-+ color_map[5]=A_STANDOUT;
-+ }
-+#endif
-+
-+ showmainview();
-+ refresh();
-+
-+#ifdef _WIN32
-+ DWORD nextupd=GetTickCount()+250;
-+#else
-+ time_t nextupd=time(NULL)+1;
-+#endif
-+
-+ while (g_client->GetStatus() >= 0 && !g_done
-+#ifdef _WIN32
-+ && IsWindow(CURSES_INSTANCE->cursesCtx.m_hwnd)
-+#endif
-+
-+ )
-+ {
-+ if (g_client->Run())
-+ {
-+#ifdef _WIN32
-+ MSG msg;
-+ while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
-+ {
-+ TranslateMessage(&msg);
-+ DispatchMessage(&msg);
-+ }
-+ Sleep(1);
-+#else
-+ struct timespec ts={0,1000*1000};
-+ nanosleep(&ts,NULL);
-+#endif
-+
-+ int a=getch();
-+#ifdef _MAC
-+ {
-+ static timeval last_t;
-+ static int stage;
-+ timeval now;
-+ gettimeofday(&now,NULL);
-+ if (a != ERR || (stage &&
-+ ((long long) (((now.tv_sec-last_t.tv_sec) * 1000) + ((now.tv_usec-last_t.tv_usec)/1000)))>333
-+
-+ ))
-+ {
-+ last_t = now;
-+ if (!stage && a == 27) { a=ERR; stage++; }
-+ else if (stage==1 && a == 79) { a=ERR; stage++; }
-+ else if (stage==2 && a >= 80 && a <= 91)
-+ {
-+ a = KEY_F(a-79);
-+ stage=0;
-+ }
-+ else if (stage) { a = 27; stage=0; }
-+ }
-+ }
-+ if (a == 127) a = KEY_BACKSPACE;
-+ if (a == KEY_F(7)) a = KEY_F(11);
-+ if (a == KEY_F(8)) a = KEY_F(12);
-+#endif
-+ if (a!=ERR)
-+ {
-+ if (!g_ui_state) switch (a)
-+ {
-+ case KEY_LEFT:
-+ if (g_sel_x > 0)
-+ {
-+ g_sel_x--;
-+ showmainview();
-+ }
-+ break;
-+ case KEY_RIGHT:
-+ {
-+ g_sel_x++;
-+ showmainview();
-+ }
-+ break;
-+ case KEY_UP:
-+ showmainview(false,-1);
-+ break;
-+ case KEY_DOWN:
-+ showmainview(false,1);
-+ break;
-+ case '\r': case ' ':
-+ if (!g_ui_inchat)
-+ {
-+ showmainview(true);
-+ break;
-+ }
-+ default:
-+ if (g_ui_inchat)
-+ {
-+ switch (a)
-+ {
-+ case KEY_PPAGE:
-+ g_chat_scroll+=LINES/4-2;
-+ showmainview();
-+ break;
-+ case KEY_NPAGE:
-+ g_chat_scroll-=LINES/4-2;
-+ if (g_chat_scroll<0)g_chat_scroll=0;
-+ showmainview();
-+ break;
-+ case '\r':
-+ if (m_chatinput_str[0])
-+ {
-+ if (m_chatinput_str[0] == '/')
-+ {
-+ if (!strncasecmp(m_chatinput_str,"/me ",4))
-+ {
-+ g_client->ChatMessage_Send("MSG",m_chatinput_str);
-+ }
-+ else if (!strncasecmp(m_chatinput_str,"/topic ",7)||
-+ !strncasecmp(m_chatinput_str,"/kick ",6) ||
-+ !strncasecmp(m_chatinput_str,"/bpm ",5) ||
-+ !strncasecmp(m_chatinput_str,"/bpi ",5)
-+ ) // alias to /admin *
-+ {
-+ g_client->ChatMessage_Send("ADMIN",m_chatinput_str+1);
-+ }
-+ else if (!strncasecmp(m_chatinput_str,"/admin ",7))
-+ {
-+ char *p=m_chatinput_str+7;
-+ while (*p == ' ') p++;
-+ g_client->ChatMessage_Send("ADMIN",p);
-+ }
-+ else if (!strncasecmp(m_chatinput_str,"/msg ",5))
-+ {
-+ char *p=m_chatinput_str+5;
-+ while (*p == ' ') p++;
-+ char *n=p;
-+ while (*p && *p != ' ') p++;
-+ if (*p == ' ') *p++=0;
-+ while (*p == ' ') p++;
-+ if (*p)
-+ {
-+ g_client->ChatMessage_Send("PRIVMSG",n,p);
-+ WDL_String tmp;
-+ tmp.Set("-> *");
-+ tmp.Append(n);
-+ tmp.Append("* ");
-+ tmp.Append(p);
-+ addChatLine(NULL,tmp.Get());
-+ }
-+ else
-+ {
-+ addChatLine("","error: /msg requires a username and a message.");
-+ }
-+ }
-+ else
-+ {
-+ addChatLine("","error: unknown command.");
-+ }
-+ }
-+ else
-+ {
-+ g_client->ChatMessage_Send("MSG",m_chatinput_str);
-+ }
-+
-+
-+ m_chatinput_str[0]=0;
-+ showmainview();
-+ }
-+ break;
-+ case 27:
-+ {
-+ m_chatinput_str[0]=0;
-+ showmainview();
-+ }
-+ break;
-+ case KEY_BACKSPACE:
-+ if (m_chatinput_str[0]) m_chatinput_str[strlen(m_chatinput_str)-1]=0;
-+ showmainview();
-+ break;
-+ default:
-+ if (VALIDATE_TEXT_CHAR(a))
-+ {
-+ int l=strlen(m_chatinput_str);
-+ if (l < (int)sizeof(m_chatinput_str)-1) { m_chatinput_str[l]=a; m_chatinput_str[l+1]=0; }
-+ showmainview();
-+ }
-+ break;
-+ }
-+ }
-+ break;
-+ }
-+ else if (g_ui_state == 1)
-+ {
-+ switch (a)
-+ {
-+ case KEY_LEFT:
-+ case KEY_RIGHT:
-+ {
-+ float pan;
-+ int ok=0;
-+ if (g_ui_voltweakstate_channel == -2) { ok=1; pan=(float)g_client->config_masterpan; }
-+ else if (g_ui_voltweakstate_channel == -1) { pan=(float)g_client->config_metronome_pan; ok=1; }
-+ else if (g_ui_voltweakstate_channel >= 1024)
-+ ok=!!g_client->GetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, NULL,NULL,&pan,NULL);
-+ else ok=!g_client->GetLocalChannelMonitoring(g_ui_voltweakstate_channel,NULL,&pan,NULL,NULL);
-+
-+ if (ok)
-+ {
-+ pan += a == KEY_LEFT ? -0.01f : 0.01f;
-+ if (pan > 1.0f) pan=1.0f;
-+ else if (pan < -1.0f) pan=-1.0f;
-+ if (g_ui_voltweakstate_channel == -2) g_client->config_masterpan=pan;
-+ else if (g_ui_voltweakstate_channel == -1) g_client->config_metronome_pan=pan;
-+ else if (g_ui_voltweakstate_channel>=1024)
-+ g_client->SetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, false,false,false,0.0f,true,pan,false,false,false,false);
-+ else
-+ g_client->SetLocalChannelMonitoring(g_ui_voltweakstate_channel,false,0.0f,true,pan,false,false,false,false);
-+ showmainview();
-+ }
-+ }
-+ break;
-+ case KEY_PPAGE:
-+ case KEY_UP:
-+ case KEY_NPAGE:
-+ case KEY_DOWN:
-+ {
-+ float vol;
-+ int ok=0;
-+ if (g_ui_voltweakstate_channel == -2) { ok=1; vol=(float)g_client->config_mastervolume; }
-+ else if (g_ui_voltweakstate_channel == -1) { vol=(float)g_client->config_metronome; ok=1; }
-+ else if (g_ui_voltweakstate_channel >= 1024)
-+ ok=!!g_client->GetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, NULL,&vol,NULL,NULL,NULL);
-+ else ok=!g_client->GetLocalChannelMonitoring(g_ui_voltweakstate_channel,&vol,NULL,NULL,NULL);
-+
-+ if (ok)
-+ {
-+ vol=(float) VAL2DB(vol);
-+ float sc=a == KEY_PPAGE || a == KEY_NPAGE? 4.0f : 0.5f;
-+ if (a == KEY_DOWN || a == KEY_NPAGE) sc=-sc;
-+ vol += sc;
-+ if (vol > 20.0f) vol=20.0f;
-+ else if (vol < -120.0f) vol=-120.0f;
-+ vol=(float) DB2VAL(vol);
-+ if (g_ui_voltweakstate_channel == -2) g_client->config_mastervolume=vol;
-+ else if (g_ui_voltweakstate_channel == -1) g_client->config_metronome=vol;
-+ else if (g_ui_voltweakstate_channel>=1024)
-+ g_client->SetUserChannelState((g_ui_voltweakstate_channel-1024)/64,g_ui_voltweakstate_channel%64, false,false,true,vol,false,0.0f,false,false,false,false);
-+ else
-+ g_client->SetLocalChannelMonitoring(g_ui_voltweakstate_channel,true,vol,false,0.0f,false,false,false,false);
-+ showmainview();
-+ }
-+ }
-+ break;
-+ case 27: case '\r':
-+ {
-+ g_ui_state=0;
-+ showmainview();
-+ }
-+ break;
-+ }
-+ }
-+ else if (g_ui_state == 3)
-+ {
-+ switch (a)
-+ {
-+ case KEY_PPAGE:
-+ case KEY_UP:
-+ case KEY_LEFT:
-+ {
-+ int ch=0;
-+ g_client->GetLocalChannelInfo(g_ui_locrename_ch,&ch,NULL,NULL);
-+ if (ch > 0)
-+ {
-+ ch--;
-+ g_client->SetLocalChannelInfo(g_ui_locrename_ch,NULL,true,ch,false,0,false,false);
-+ g_client->NotifyServerOfChannelChange();
-+ showmainview();
-+ }
-+ }
-+ break;
-+ case KEY_NPAGE:
-+ case KEY_DOWN:
-+ case KEY_RIGHT:
-+ {
-+ int ch=0;
-+ g_client->GetLocalChannelInfo(g_ui_locrename_ch,&ch,NULL,NULL);
-+ if (ch < g_audio->m_innch)
-+ {
-+ ch++;
-+ g_client->SetLocalChannelInfo(g_ui_locrename_ch,NULL,true,ch,false,0,false,false);
-+ g_client->NotifyServerOfChannelChange();
-+ showmainview();
-+ }
-+ }
-+ break;
-+
-+ case 27: case '\r':
-+ {
-+ g_ui_state=0;
-+ showmainview();
-+ }
-+ break;
-+ }
-+ }
-+ else if (g_ui_state == 2 || g_ui_state == 4)
-+ {
-+ switch (a)
-+ {
-+ case '\r':
-+ if (m_lineinput_str[0])
-+ {
-+ if (g_ui_state == 4)
-+ {
-+ g_client->SetLocalChannelInfo(g_ui_locrename_ch,m_lineinput_str,false,0,false,0,false,false);
-+ g_client->NotifyServerOfChannelChange();
-+ }
-+ }
-+ g_ui_state=0;
-+ showmainview();
-+ break;
-+ case 27:
-+ {
-+ g_ui_state=0;
-+ showmainview();
-+ }
-+ break;
-+ case KEY_BACKSPACE:
-+ if (m_lineinput_str[0]) m_lineinput_str[strlen(m_lineinput_str)-1]=0;
-+ showmainview();
-+ g_ui_state=4;
-+ break;
-+ default:
-+ if (VALIDATE_TEXT_CHAR(a) && (g_ui_state != 3 || (a >= '0' && a <= '9'))) //fucko: 9 once we have > 2ch
-+ {
-+ int l=strlen(m_lineinput_str);
-+ if (g_ui_state == 2)
-+ {
-+ l=0;
-+ g_ui_state=4;
-+ }
-+
-+ if (l < (int)sizeof(m_lineinput_str)-1) { m_lineinput_str[l]=a; m_lineinput_str[l+1]=0; }
-+ showmainview();
-+ }
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (g_ui_state < 2 && (g_need_disp_update||g_client->HasUserInfoChanged()||
-+#ifdef _WIN32
-+GetTickCount()>=nextupd
-+#else
-+time(NULL) >= nextupd
-+#endif
-+
-+))
-+ {
-+#ifdef _WIN32
-+ nextupd=GetTickCount()+1000;
-+#else
-+ nextupd=time(NULL)+1;
-+#endif
-+ g_need_disp_update=0;
-+ showmainview();
-+ }
-+ else drawstatusbar();
-+ }
-+
-+ }
-+
-+ erase();
-+ refresh();
-+
-+ // shut down curses
-+ endwin();
-+
-+ switch (g_client->GetStatus())
-+ {
-+ case NJClient::NJC_STATUS_OK:
-+ break;
-+ case NJClient::NJC_STATUS_INVALIDAUTH:
-+ printf("ERROR: invalid login/password\n");
-+ break;
-+ case NJClient::NJC_STATUS_CANTCONNECT:
-+ printf("ERROR: failed connecting to host\n");
-+ break;
-+ case NJClient::NJC_STATUS_PRECONNECT:
-+ printf("ERROR: failed connect\n");
-+ break;
-+ case NJClient::NJC_STATUS_DISCONNECTED:
-+ printf("ERROR: disconnected from host\n");
-+ break;
-+
-+ default:
-+ printf("exiting on status %d\n",g_client->GetStatus());
-+ break;
-+ }
-+ if (g_client->GetErrorStr()[0])
-+ {
-+ printf("Server gave explanation: %s\n",g_client->GetErrorStr());
-+ }
-+
-+
-+ printf("Shutting down\n");
-+
-+ delete g_audio;
-+
-+
-+ delete g_client->waveWrite;
-+ g_client->waveWrite=0;
-+
-+
-+ // save local channel state
-+ {
-+ FILE *fp=fopen("ninjam.config","wt");
-+ int x=0;
-+ if (fp)
-+ {
-+ fprintf(fp,"master mastervol %f masterpan %f metrovol %f metropan %f mastermute %d metromute %d\n",
-+ g_client->config_mastervolume,g_client->config_masterpan,g_client->config_metronome,g_client->config_metronome_pan,
-+ g_client->config_mastermute,g_client->config_metronome_mute);
-+
-+
-+
-+ for (x = 0;;x++)
-+ {
-+ int a=g_client->EnumLocalChannels(x);
-+ if (a<0) break;
-+
-+
-+ int sch=0;
-+ bool bc=0;
-+ void *has_jesus=0;
-+ char *lcn;
-+ float v=0.0f,p=0.0f;
-+ bool m=0,s=0;
-+
-+ lcn=g_client->GetLocalChannelInfo(a,&sch,NULL,&bc);
-+ g_client->GetLocalChannelMonitoring(a,&v,&p,&m,&s);
-+ g_client->GetLocalChannelProcessor(a,NULL,&has_jesus);
-+
-+ char *ptr=lcn;
-+ while (*ptr)
-+ {
-+ if (*ptr == '`') *ptr='\'';
-+ ptr++;
-+ }
-+ fprintf(fp,"local %d source %d bc %d mute %d solo %d volume %f pan %f jesus %d name `%s`\n",a,sch,bc,m,s,v,p,!!has_jesus,lcn);
-+ }
-+ fclose(fp);
-+ }
-+ }
-+
-+
-+ // delete all effects processors in g_client
-+ {
-+ int x=0;
-+ for (x = 0;;x++)
-+ {
-+ int a=g_client->EnumLocalChannels(x);
-+ if (a<0) break;
-+#ifdef _WIN32
-+ void *i=0;
-+ g_client->GetLocalChannelProcessor(a,NULL,&i);
-+ if (i) deleteJesusonicProc(i,a);
-+ g_client->SetLocalChannelProcessor(a,NULL,NULL);
-+#endif
-+ }
-+ }
-+
-+
-+ delete g_client;
-+
-+
-+#ifdef _WIN32
-+ ///// jesusonic stuff
-+ if (jesus_hDllInst) FreeLibrary(jesus_hDllInst);
-+ jesus_hDllInst=0;
-+ JesusonicAPI=0;
-+
-+#endif
-+
-+ if (g_nssf)
-+ {
-+ int n;
-+ for (n = 0; n < 16; n ++)
-+ {
-+ WDL_String s(sessiondir.Get());
-+ char buf[32];
-+ sprintf(buf,"%x",n);
-+ s.Append(buf);
-+
-+ {
-+ WDL_DirScan ds;
-+ if (!ds.First(s.Get()))
-+ {
-+ do
-+ {
-+ if (ds.GetCurrentFN()[0] != '.')
-+ {
-+ WDL_String t;
-+ ds.GetCurrentFullFN(&t);
-+ unlink(t.Get());
-+ }
-+ }
-+ while (!ds.Next());
-+ }
-+ }
-+#ifdef _WIN32
-+ RemoveDirectory(s.Get());
-+#else
-+ rmdir(s.Get());
-+#endif
-+ }
-+ }
-+ if (!sessionspec)
-+ {
-+#ifdef _WIN32
-+ RemoveDirectory(sessiondir.Get());
-+#else
-+ rmdir(sessiondir.Get());
-+#endif
-+
-+ }
-+
-+ JNL::close_socketlib();
-+ return 0;
-+}
-diff -Naur ninjam-cclient-0.01a/src/cursesclient/ninjam.config ninjam/src/cursesclient/ninjam.config
---- ninjam-cclient-0.01a/src/cursesclient/ninjam.config 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/cursesclient/ninjam.config 2006-01-09 21:37:34.000000000 +0000
-@@ -0,0 +1,3 @@
-+master mastervol 1.000000 masterpan 0.000000 metrovol 0.500000 metropan 0.000000 mastermute 0 metromute 1
-+local 0 source 0 bc 1 mute 0 solo 0 volume 1.000000 pan 0.000000 jesus 0 name `hydrogen`
-+local 1 source 1 bc 1 mute 0 solo 0 volume 1.000000 pan 0.000000 jesus 0 name `albino`
-diff -Naur ninjam-cclient-0.01a/src/mpb.cpp ninjam/src/mpb.cpp
---- ninjam-cclient-0.01a/src/mpb.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/mpb.cpp 2006-01-18 19:31:40.926012160 +0000
-@@ -0,0 +1,890 @@
-+/*
-+ NINJAM - mpb.cpp
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This file provides implementation of Message Parser and Builder (mpb_)
-+ classes for constructing and parsing Net_Messages.
-+
-+*/
-+
-+
-+#ifdef _WIN32
-+#include <windows.h>
-+#else
-+#include <stdlib.h>
-+#include <memory.h>
-+#endif
-+
-+#include "mpb.h"
-+
-+
-+
-+// MESSAGE_SERVER_AUTH_CHALLENGE
-+int mpb_server_auth_challenge::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_SERVER_AUTH_CHALLENGE) return -1;
-+ if (msg->get_size() < 4+4+(int)sizeof(challenge)) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ memcpy(challenge,p,sizeof(challenge));
-+ p+=sizeof(challenge);
-+
-+ server_caps = ((int)*p++);
-+ server_caps |= ((int)*p++)<<8;
-+ server_caps |= ((int)*p++)<<16;
-+ server_caps |= ((int)*p++)<<24;
-+
-+ protocol_version = ((int)*p++);
-+ protocol_version |= ((int)*p++)<<8;
-+ protocol_version |= ((int)*p++)<<16;
-+ protocol_version |= ((int)*p++)<<24;
-+
-+ if (server_caps&1)
-+ {
-+ char *s=(char*)p;
-+ while (p-(unsigned char *)msg->get_data() < msg->get_size())
-+ {
-+ if (!*p)
-+ {
-+ license_agreement=s;
-+ break;
-+ }
-+ p++;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+Net_Message *mpb_server_auth_challenge::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_SERVER_AUTH_CHALLENGE);
-+
-+ nm->set_size(sizeof(challenge) + 8 + (license_agreement?strlen(license_agreement)+1:0));
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+
-+ memcpy(p,challenge,sizeof(challenge));
-+ p+=sizeof(challenge);
-+
-+ int sc=server_caps;
-+ if (license_agreement) sc|=1;
-+ else sc&=~1;
-+
-+ *p++ = sc&0xff;
-+ *p++ = (sc>>8)&0xff;
-+ *p++ = (sc>>16)&0xff;
-+ *p++ = (sc>>24)&0xff;
-+
-+ *p++ = protocol_version&0xff;
-+ *p++ = (protocol_version>>8)&0xff;
-+ *p++ = (protocol_version>>16)&0xff;
-+ *p++ = (protocol_version>>24)&0xff;
-+
-+
-+ if (license_agreement)
-+ {
-+ strcpy((char*)p,license_agreement);
-+ p+=strlen(license_agreement);
-+ *p++=0;
-+ }
-+
-+
-+ return nm;
-+}
-+
-+
-+
-+// MESSAGE_SERVER_AUTH_REPLY
-+int mpb_server_auth_reply::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_SERVER_AUTH_REPLY) return -1;
-+ if (msg->get_size() < 1) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ flag=*p++;
-+ if (msg->get_size()>1)
-+ {
-+ char *t=(char*)p;
-+ while (p-(unsigned char *)msg->get_data() < msg->get_size() && *p) p++;
-+
-+ if (p-(unsigned char *)msg->get_data() < msg->get_size())
-+ {
-+ errmsg=t;
-+
-+ p++;
-+ if (p-(unsigned char *)msg->get_data() < msg->get_size())
-+ {
-+ maxchan=*p++;
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+Net_Message *mpb_server_auth_reply::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_SERVER_AUTH_REPLY);
-+
-+ nm->set_size(errmsg?strlen(errmsg)+1+1+1:1);
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+
-+ *p++=flag;
-+ if (errmsg)
-+ {
-+ strcpy((char*)p,errmsg);
-+ p+=strlen(errmsg)+1;
-+ *p++ = maxchan;
-+ }
-+
-+ return nm;
-+}
-+
-+
-+// MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY
-+int mpb_server_config_change_notify::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY) return -1;
-+ if (msg->get_size() < 4) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ beats_minute = *p++;
-+ beats_minute |= ((int)*p++)<<8;
-+ beats_interval = *p++;
-+ beats_interval |= ((int)*p++)<<8;
-+
-+ return 0;
-+}
-+
-+Net_Message *mpb_server_config_change_notify::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY);
-+
-+ nm->set_size(4);
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+
-+ *p++=beats_minute&0xff;
-+ *p++=(beats_minute>>8)&0xff;
-+ *p++=beats_interval&0xff;
-+ *p++=(beats_interval>>8)&0xff;
-+
-+ return nm;
-+}
-+
-+
-+// MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY
-+int mpb_server_userinfo_change_notify::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY) return -1;
-+ if (msg->get_size() < 1) return 1;
-+
-+ m_intmsg = msg;
-+ return 0;
-+}
-+
-+Net_Message *mpb_server_userinfo_change_notify::build()
-+{
-+ if (m_intmsg)
-+ {
-+ Net_Message *n=m_intmsg;
-+ m_intmsg=0;
-+ return n;
-+ }
-+
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY);
-+ nm->set_size(0);
-+
-+ return nm;
-+}
-+
-+
-+void mpb_server_userinfo_change_notify::build_add_rec(int isActive, int channelid,
-+ short volume, int pan, int flags, char *username, char *chname)
-+{
-+ int size=1+ // is remove
-+ 1+ // channel index
-+ 2+ // volume
-+ 1+ // pan
-+ 1+ // flags
-+ strlen(username?username:"")+1+strlen(chname?chname:"")+1;
-+
-+ if (!m_intmsg)
-+ {
-+ m_intmsg = new Net_Message;
-+ m_intmsg->set_type(MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY);
-+ }
-+ int oldsize=m_intmsg->get_size();
-+ m_intmsg->set_size(size+oldsize);
-+ unsigned char *p=(unsigned char *)m_intmsg->get_data();
-+ if (p)
-+ {
-+ p+=oldsize;
-+ *p++=!!isActive;
-+
-+ if (channelid < 0) channelid=0;
-+ else if (channelid>255)channelid=255;
-+ *p++=channelid;
-+
-+ *p++=volume&0xff;
-+ *p++=(volume>>8)&0xff;
-+
-+ if (pan<-128) pan=-128;
-+ else if (pan>127)pan=127;
-+ *p++=(unsigned char)pan;
-+
-+ *p++=(unsigned char)flags;
-+
-+ strcpy((char*)p,username);
-+ p+=strlen(username)+1;
-+ strcpy((char*)p,chname);
-+ p+=strlen(chname)+1;
-+ }
-+}
-+
-+
-+// returns offset of next item on success, or <= 0 if out of items
-+int mpb_server_userinfo_change_notify::parse_get_rec(int offs, int *isActive, int *channelid, short *volume,
-+ int *pan, int *flags, char **username, char **chname)
-+{
-+ int hdrsize=1+ // is remove
-+ 1+ // channel index
-+ 2+ // volume
-+ 1+ // pan
-+ 1; // flags
-+
-+ if (!m_intmsg) return 0;
-+ unsigned char *p=(unsigned char *)m_intmsg->get_data();
-+ int len=m_intmsg->get_size()-offs;
-+ if (!p || len < hdrsize+2) return 0;
-+ p+=offs;
-+
-+ unsigned char *hdrbuf=p;
-+ char *unp;
-+ char *cnp;
-+
-+ if (len < hdrsize+2) return 0;
-+ hdrbuf=p;
-+ len -= hdrsize;
-+ unp=(char *)hdrbuf+hdrsize;
-+ cnp=unp;
-+ while (*cnp)
-+ {
-+ cnp++;
-+ if (!len--) return 0;
-+ }
-+ cnp++;
-+ if (!len--) return 0;
-+
-+ p=(unsigned char *)cnp;
-+ while (*p)
-+ {
-+ p++;
-+ if (!len--) return 0;
-+ }
-+ p++;
-+ if (!len--) return 0;
-+
-+ *isActive=(int)*hdrbuf++;
-+ *channelid=(int)*hdrbuf++;
-+ *volume=(int)*hdrbuf++;
-+ *volume |= ((int)*hdrbuf++)<<8;
-+ *pan = (int) *hdrbuf++;
-+ *flags = (int) *hdrbuf++;
-+
-+ *username = unp;
-+ *chname = cnp;
-+
-+
-+ return p - (unsigned char *)m_intmsg->get_data();
-+}
-+
-+
-+// MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN
-+int mpb_server_download_interval_begin::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN) return -1;
-+ if (msg->get_size() < 25+1) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ memcpy(guid,p,sizeof(guid));
-+ p+=sizeof(guid);
-+ estsize = (int)*p++;
-+ estsize |= ((int)*p++)<<8;
-+ estsize |= ((int)*p++)<<16;
-+ estsize |= ((int)*p++)<<24;
-+ fourcc = (unsigned int)*p++;
-+ fourcc |= ((unsigned int)*p++)<<8;
-+ fourcc |= ((unsigned int)*p++)<<16;
-+ fourcc |= ((unsigned int)*p++)<<24;
-+ chidx = (int)*p++;
-+ int len=msg->get_size()-25;
-+
-+ username=(char *)p;
-+
-+
-+ // validate null termination for now
-+ while (len)
-+ {
-+ if (!*p) break;
-+ p++;
-+ len--;
-+ }
-+ if (!len) return -1;
-+
-+ return 0;
-+}
-+
-+
-+Net_Message *mpb_server_download_interval_begin::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN);
-+
-+ nm->set_size(25+strlen(username?username:"")+1);
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+
-+ memcpy(p,guid,sizeof(guid));
-+ p+=sizeof(guid);
-+ *p++=(unsigned char)((estsize)&0xff);
-+ *p++=(unsigned char)((estsize>>8)&0xff);
-+ *p++=(unsigned char)((estsize>>16)&0xff);
-+ *p++=(unsigned char)((estsize>>24)&0xff);
-+ *p++=(unsigned char)((fourcc)&0xff);
-+ *p++=(unsigned char)((fourcc>>8)&0xff);
-+ *p++=(unsigned char)((fourcc>>16)&0xff);
-+ *p++=(unsigned char)((fourcc>>24)&0xff);
-+ *p++=(unsigned char)((chidx)&0xff);
-+
-+ strcpy((char *)p,username?username:"");
-+
-+
-+ return nm;
-+}
-+
-+
-+// MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE
-+int mpb_server_download_interval_write::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE) return -1;
-+ if (msg->get_size() < 17) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ memcpy(guid,p,sizeof(guid));
-+ p+=sizeof(guid);
-+ flags = (char)*p++;
-+
-+ audio_data = p;
-+ audio_data_len = msg->get_size()-17;
-+
-+ return 0;
-+}
-+
-+
-+Net_Message *mpb_server_download_interval_write::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE);
-+
-+ nm->set_size(17+(audio_data?audio_data_len:0));
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+ memcpy(p,guid,sizeof(guid));
-+ p+=sizeof(guid);
-+ *p++=(unsigned char) flags;
-+
-+ if (audio_data&&audio_data_len) memcpy(p,audio_data,audio_data_len);
-+
-+ return nm;
-+}
-+
-+
-+
-+
-+
-+
-+/////////////////////////////////////////////////////////////////////////
-+//////////// client to server messages
-+/////////////////////////////////////////////////////////////////////////
-+
-+
-+// MESSAGE_CLIENT_AUTH_USER
-+int mpb_client_auth_user::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_CLIENT_AUTH_USER) return -1;
-+ if (msg->get_size() < (int)sizeof(passhash)+1) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+ int len=msg->get_size();
-+
-+ memcpy(passhash,p,sizeof(passhash));
-+ p+=sizeof(passhash);
-+ len -= sizeof(passhash);
-+
-+ username=(char *)p;
-+ while (*p && len>0)
-+ {
-+ p++;
-+ len--;
-+ }
-+ if (!len) return 3;
-+ p++;
-+ len--;
-+
-+ if (len < 8) return 3;
-+
-+ client_caps = ((int)*p++);
-+ client_caps |= ((int)*p++)<<8;
-+ client_caps |= ((int)*p++)<<16;
-+ client_caps |= ((int)*p++)<<24;
-+
-+ client_version = ((int)*p++);
-+ client_version |= ((int)*p++)<<8;
-+ client_version |= ((int)*p++)<<16;
-+ client_version |= ((int)*p++)<<24;
-+
-+ //printf("bla (len=%d, caps=%d) decoded client version %08x\n",len,client_caps,client_version);
-+
-+ return 0;
-+}
-+
-+Net_Message *mpb_client_auth_user::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_CLIENT_AUTH_USER);
-+
-+ nm->set_size(sizeof(passhash) + (username?strlen(username):0) + 1 + 4 + 4);
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+
-+ memcpy(p,passhash,sizeof(passhash));
-+ p+=sizeof(passhash);
-+
-+ strcpy((char*)p,username?username:"");
-+ p+=strlen(username?username:"")+1;
-+
-+ *p++=(client_caps&0xff);
-+ *p++=(client_caps&0xff00)>>8;
-+ *p++=(client_caps&0xff0000)>>16;
-+ *p++=(client_caps&0xff000000)>>24;
-+
-+ *p++=(client_version&0xff);
-+ *p++=(client_version&0xff00)>>8;
-+ *p++=(client_version&0xff0000)>>16;
-+ *p++=(client_version&0xff000000)>>24;
-+
-+ return nm;
-+}
-+
-+
-+// MESSAGE_CLIENT_SET_USERMASK
-+int mpb_client_set_usermask::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_CLIENT_SET_USERMASK) return -1;
-+ if (msg->get_size() < 1) return 1;
-+
-+ m_intmsg = msg;
-+ return 0;
-+}
-+
-+Net_Message *mpb_client_set_usermask::build()
-+{
-+ if (m_intmsg)
-+ {
-+ Net_Message *n=m_intmsg;
-+ m_intmsg=0;
-+ return n;
-+ }
-+
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_CLIENT_SET_USERMASK);
-+ nm->set_size(0);
-+
-+ return nm;
-+}
-+
-+
-+void mpb_client_set_usermask::build_add_rec(char *username, unsigned int chflags)
-+{
-+ int size=4+strlen(username?username:"")+1;
-+
-+ if (!m_intmsg)
-+ {
-+ m_intmsg = new Net_Message;
-+ m_intmsg->set_type(MESSAGE_CLIENT_SET_USERMASK);
-+ }
-+ int oldsize=m_intmsg->get_size();
-+ m_intmsg->set_size(size+oldsize);
-+ unsigned char *p=(unsigned char *)m_intmsg->get_data();
-+ if (p)
-+ {
-+ p+=oldsize;
-+
-+ strcpy((char*)p,username);
-+ p+=strlen(username)+1;
-+
-+ *p++=chflags&0xff;
-+ *p++=(chflags>>8)&0xff;
-+ *p++=(chflags>>16)&0xff;
-+ *p++=(chflags>>24)&0xff;
-+ }
-+}
-+
-+
-+// returns offset of next item on success, or <= 0 if out of items
-+int mpb_client_set_usermask::parse_get_rec(int offs, char **username, unsigned int *chflags)
-+{
-+ if (!m_intmsg) return 0;
-+ unsigned char *p=(unsigned char *)m_intmsg->get_data();
-+ int len=m_intmsg->get_size()-offs;
-+ if (!p || len < 5) return 0;
-+ p+=offs;
-+
-+ *username=(char*)p;
-+ while (*p && len > 0)
-+ {
-+ len--;
-+ p++;
-+ }
-+ p++;
-+ len--;
-+
-+ if (len<4) return -1;
-+
-+ *chflags = ((int)*p++);
-+ *chflags |= ((int)*p++)<<8;
-+ *chflags |= ((int)*p++)<<16;
-+ *chflags |= ((int)*p++)<<24;
-+
-+ return p - (unsigned char *)m_intmsg->get_data();
-+}
-+
-+
-+// MESSAGE_CLIENT_SET_CHANNEL_INFO
-+int mpb_client_set_channel_info::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_CLIENT_SET_CHANNEL_INFO) return -1;
-+
-+ m_intmsg = msg;
-+
-+ return 0;
-+}
-+
-+Net_Message *mpb_client_set_channel_info::build()
-+{
-+ if (m_intmsg)
-+ {
-+ Net_Message *n=m_intmsg;
-+ m_intmsg=0;
-+ return n;
-+ }
-+
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_CLIENT_SET_CHANNEL_INFO);
-+ nm->set_size(0);
-+
-+ return nm;
-+}
-+
-+
-+void mpb_client_set_channel_info::build_add_rec(char *chname, short volume, int pan, int flags)
-+{
-+ int size=mpisize+strlen(chname?chname:"")+1;
-+
-+ if (!m_intmsg)
-+ {
-+ m_intmsg = new Net_Message;
-+ m_intmsg->set_type(MESSAGE_CLIENT_SET_CHANNEL_INFO);
-+ m_intmsg->set_size(2);
-+ unsigned char *p=(unsigned char*)m_intmsg->get_data();
-+ if (!p) return;
-+ *p++ = mpisize&0xff;
-+ *p++ = (mpisize>>8)&0xff;
-+ }
-+ int oldsize=m_intmsg->get_size();
-+ m_intmsg->set_size(size+oldsize);
-+ unsigned char *p=(unsigned char *)m_intmsg->get_data();
-+ if (p)
-+ {
-+ p+=oldsize;
-+
-+ strcpy((char*)p,chname);
-+ p+=strlen(chname)+1;
-+ if (pan < -128) pan=-128;
-+ else if (pan > 127) pan=127;
-+ if (mpisize>0) *p++=(volume)&0xff;
-+ if (mpisize>1) *p++=(volume>>8)&0xff;
-+ if (mpisize>2) *p++=(unsigned char)pan;
-+ if (mpisize>3) *p++=(unsigned char)flags;
-+ if (mpisize>4)
-+ memset(p,0,mpisize-4);
-+
-+ }
-+}
-+
-+
-+// returns offset of next item on success, or <= 0 if out of items
-+int mpb_client_set_channel_info::parse_get_rec(int offs, char **chname, short *volume, int *pan, int *flags)
-+{
-+ if (!m_intmsg) return 0;
-+ unsigned char *p=(unsigned char *)m_intmsg->get_data();
-+ if (!p || m_intmsg->get_size() <= 2) return 0;
-+ int len=m_intmsg->get_size()-offs;
-+
-+ mpisize=(int)p[0] | (((int)p[1])<<8);
-+ if (len < mpisize) return 0;
-+
-+ p+=offs+2;
-+
-+ *chname=(char*)p;
-+ while (*p && len > 0)
-+ {
-+ len--;
-+ p++;
-+ }
-+ p++;
-+ len--;
-+
-+ if (len<mpisize) return -1;
-+
-+ if (mpisize>1)
-+ {
-+ *volume=(int)p[0];
-+ *volume|=((int)p[1])<<8;
-+ }
-+ else *volume=0;
-+ if (mpisize>2) *pan=(int)p[2];
-+ else *pan=0;
-+ if (mpisize>3) *flags=(int)p[3];
-+ else *flags=0;
-+
-+ return (p+mpisize) - ((unsigned char *)m_intmsg->get_data()+2);
-+}
-+
-+// MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN
-+
-+int mpb_client_upload_interval_begin::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN) return -1;
-+ if (msg->get_size() < 25) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ memcpy(guid,p,sizeof(guid));
-+ p+=sizeof(guid);
-+ estsize = (int)*p++;
-+ estsize |= ((int)*p++)<<8;
-+ estsize |= ((int)*p++)<<16;
-+ estsize |= ((int)*p++)<<24;
-+ fourcc = (unsigned int)*p++;
-+ fourcc |= ((unsigned int)*p++)<<8;
-+ fourcc |= ((unsigned int)*p++)<<16;
-+ fourcc |= ((unsigned int)*p++)<<24;
-+ chidx = (int)*p++;
-+
-+ return 0;
-+}
-+
-+
-+Net_Message *mpb_client_upload_interval_begin::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN);
-+
-+ nm->set_size(25);
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+
-+ memcpy(p,guid,sizeof(guid));
-+ p+=sizeof(guid);
-+ *p++=(unsigned char)((estsize)&0xff);
-+ *p++=(unsigned char)((estsize>>8)&0xff);
-+ *p++=(unsigned char)((estsize>>16)&0xff);
-+ *p++=(unsigned char)((estsize>>24)&0xff);
-+ *p++=(unsigned char)((fourcc)&0xff);
-+ *p++=(unsigned char)((fourcc>>8)&0xff);
-+ *p++=(unsigned char)((fourcc>>16)&0xff);
-+ *p++=(unsigned char)((fourcc>>24)&0xff);
-+ *p++=(unsigned char)((chidx)&0xff);
-+
-+
-+ return nm;
-+}
-+
-+
-+// MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE
-+int mpb_client_upload_interval_write::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE) return -1;
-+ if (msg->get_size() < 17) return 1;
-+ unsigned char *p=(unsigned char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ memcpy(guid,p,sizeof(guid));
-+ p+=sizeof(guid);
-+ flags = (char)*p++;
-+
-+ audio_data = p;
-+ audio_data_len = msg->get_size()-17;
-+
-+ return 0;
-+}
-+
-+
-+Net_Message *mpb_client_upload_interval_write::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE);
-+
-+ nm->set_size(17+(audio_data?audio_data_len:0));
-+
-+ unsigned char *p=(unsigned char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+ memcpy(p,guid,sizeof(guid));
-+ p+=sizeof(guid);
-+ *p++=(unsigned char) flags;
-+
-+ if (audio_data&&audio_data_len) memcpy(p,audio_data,audio_data_len);
-+
-+ return nm;
-+}
-+
-+
-+/////////////////////////////////////////////////////////////////////////
-+//////////// bidirectional generic messages
-+/////////////////////////////////////////////////////////////////////////
-+
-+
-+// MESSAGE_CHAT_MESSAGE
-+
-+int mpb_chat_message::parse(Net_Message *msg) // return 0 on success
-+{
-+ if (msg->get_type() != MESSAGE_CHAT_MESSAGE) return -1;
-+ if (msg->get_size() < 1) return 1;
-+ char *p=(char *)msg->get_data();
-+ if (!p) return 2;
-+
-+ char *endp=(char*)msg->get_data()+msg->get_size();
-+
-+ unsigned int x;
-+ memset(parms,0,sizeof(parms));
-+ for (x = 0; x < sizeof(parms)/sizeof(parms[0]); x ++)
-+ {
-+ parms[x]=p;
-+ while (p < endp && *p) p++;
-+ p++;
-+ if (p >= endp) break;
-+ }
-+ return x?0:3;
-+}
-+
-+
-+Net_Message *mpb_chat_message::build()
-+{
-+ Net_Message *nm=new Net_Message;
-+ nm->set_type(MESSAGE_CHAT_MESSAGE);
-+
-+ unsigned int x;
-+ int sz=0;
-+ for (x = 0; x < sizeof(parms)/sizeof(parms[0]); x ++)
-+ {
-+ sz+=(parms[x]?strlen(parms[x]):0)+1;
-+ }
-+
-+ nm->set_size(sz);
-+
-+ char *p=(char *)nm->get_data();
-+
-+ if (!p)
-+ {
-+ delete nm;
-+ return 0;
-+ }
-+
-+ for (x = 0; x < sizeof(parms)/sizeof(parms[0]); x ++)
-+ {
-+ char *sp=parms[x];
-+ if (!sp) sp="";
-+ strcpy(p,sp);
-+ p+=strlen(sp)+1;
-+ }
-+
-+ return nm;
-+}
-+
-diff -Naur ninjam-cclient-0.01a/src/mpb.h ninjam/src/mpb.h
---- ninjam-cclient-0.01a/src/mpb.h 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/mpb.h 2005-08-30 03:16:06.000000000 +0000
-@@ -0,0 +1,292 @@
-+/*
-+ NINJAM - mpb.h
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This header provides message-type defines, as well as Message Parser and Builder (mpb_)
-+ classes for constructing and parsing Net_Messages.
-+
-+*/
-+
-+
-+#ifndef _MPB_H_
-+#define _MPB_H_ // mpb.h, message parsing and building
-+
-+
-+#include "netmsg.h"
-+
-+
-+#define PROTO_VER_MIN 0x00020000
-+#define PROTO_VER_MAX 0x0002ffff
-+#define PROTO_VER_CUR 0x00020000
-+
-+
-+#define MESSAGE_SERVER_AUTH_CHALLENGE 0x00
-+
-+class mpb_server_auth_challenge
-+{
-+ public:
-+ mpb_server_auth_challenge() : server_caps(0), license_agreement(0), protocol_version(0) { memset(challenge,0,sizeof(challenge)); }
-+ ~mpb_server_auth_challenge() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+
-+ // public data
-+ unsigned char challenge[8];
-+ int server_caps; // low bit is license agreement, bits 8-16 are keepalive
-+ char *license_agreement;
-+ int protocol_version; // version should be 1 to start.
-+};
-+
-+#define MESSAGE_SERVER_AUTH_REPLY 0x01
-+
-+class mpb_server_auth_reply
-+{
-+ public:
-+ mpb_server_auth_reply() : flag(0), errmsg(0), maxchan(32) { }
-+ ~mpb_server_auth_reply() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+
-+ // public data
-+ char flag; // low bit is success bit
-+ char *errmsg; // if success bit is set, and this is also set, then it is the effective username of the client
-+ char maxchan;
-+};
-+
-+
-+
-+#define MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY 0x02
-+
-+class mpb_server_config_change_notify
-+{
-+ public:
-+ mpb_server_config_change_notify() : beats_minute(120), beats_interval(32) { }
-+ ~mpb_server_config_change_notify() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+
-+ // public data
-+ int beats_minute; //bpm
-+ int beats_interval; // beats/interval
-+};
-+
-+
-+
-+#define MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY 0x03
-+
-+class mpb_server_userinfo_change_notify
-+{
-+ public:
-+ mpb_server_userinfo_change_notify() : m_intmsg(0) { }
-+ ~mpb_server_userinfo_change_notify() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build(); // if you call build_add_rec at all, you must do delete x->build(); to avoid a mem leak.
-+
-+ // public accessors
-+ // pan is -128..127
-+ // volume is dB gain, so 0=0dB, 10=1dB, -30=-3 dB, etc
-+ // flags, &1 = no default subscribe
-+ void build_add_rec(int isActive, int channelid, short volume, int pan, int flags, char *username, char *chname);
-+ int parse_get_rec(int offs, int *isActive, int *channelid, short *volume, int *pan, int *flags, char **username, char **chname); // returns offset of next item on success, or <0 if out of items
-+
-+ private:
-+
-+ Net_Message *m_intmsg;
-+};
-+
-+
-+#define MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN 0x04
-+class mpb_server_download_interval_begin
-+{
-+ public:
-+ mpb_server_download_interval_begin() : estsize(0), fourcc(0), chidx(0), username(0) { memset(guid,0,sizeof(guid)); }
-+ ~mpb_server_download_interval_begin() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+ // public data
-+ unsigned char guid[16];
-+ int estsize;
-+ unsigned int fourcc;
-+ int chidx; // only 1 byte
-+ char *username;
-+};
-+
-+
-+#define MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE 0x05
-+class mpb_server_download_interval_write
-+{
-+ public:
-+ mpb_server_download_interval_write() : flags(0), audio_data(0), audio_data_len(0) { memset(guid,0,sizeof(guid)); }
-+ ~mpb_server_download_interval_write() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+ // public data
-+ unsigned char guid[16]; // transfer id
-+ char flags; // & 1 = end
-+
-+ void *audio_data;
-+ int audio_data_len; // not encoded in, just used internally
-+};
-+
-+
-+
-+
-+#define MESSAGE_CLIENT_AUTH_USER 0x80
-+class mpb_client_auth_user
-+{
-+ public:
-+ mpb_client_auth_user() : client_caps(0), client_version(0), username(0) { memset(passhash,0,sizeof(passhash)); }
-+ ~mpb_client_auth_user() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+
-+ // public data
-+ unsigned char passhash[20];
-+ int client_caps; // low bit is agreeing to license
-+ int client_version; // client version, only present if second bit of caps is there
-+ // second bit should be set, otherwise server will disconnect anyway.
-+ char *username;
-+};
-+
-+
-+
-+#define MESSAGE_CLIENT_SET_USERMASK 0x81
-+class mpb_client_set_usermask
-+{
-+ public:
-+ mpb_client_set_usermask() : m_intmsg(0) { }
-+ ~mpb_client_set_usermask() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+
-+ void build_add_rec(char *username, unsigned int chflags);
-+ int parse_get_rec(int offs, char **username, unsigned int *chflags); // returns offset of next item on success, or <0 if out of items
-+
-+ private:
-+
-+ Net_Message *m_intmsg;
-+};
-+
-+#define MESSAGE_CLIENT_SET_CHANNEL_INFO 0x82
-+class mpb_client_set_channel_info
-+{
-+ public:
-+ mpb_client_set_channel_info() : mpisize(4), m_intmsg(0) { }
-+ ~mpb_client_set_channel_info() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+
-+ // pan is -128..127
-+ // volume is dB gain, so 0=0dB, 10=1dB, -30=-3 dB, etc
-+ // flags, &1 = no default subscribe
-+ void build_add_rec(char *chname, short volume, int pan, int flags);
-+ int parse_get_rec(int offs, char **chname, short *volume, int *pan, int *flags); // returns offset of next item on success, or <0 if out of items
-+
-+ int mpisize;
-+
-+ private:
-+
-+ Net_Message *m_intmsg;
-+};
-+
-+
-+#define MESSAGE_CLIENT_UPLOAD_INTERVAL_BEGIN 0x83
-+class mpb_client_upload_interval_begin
-+{
-+ public:
-+ mpb_client_upload_interval_begin() : estsize(0), fourcc(0), chidx(0){ memset(guid,0,sizeof(guid)); }
-+ ~mpb_client_upload_interval_begin() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+ // public data
-+ unsigned char guid[16];
-+ int estsize;
-+ unsigned int fourcc;
-+ int chidx; // only 1 byte
-+};
-+
-+
-+
-+// this uses the exact same message format as the server version
-+#define MESSAGE_CLIENT_UPLOAD_INTERVAL_WRITE 0x84
-+class mpb_client_upload_interval_write
-+{
-+ public:
-+ mpb_client_upload_interval_write() : flags(0), audio_data(0), audio_data_len(0) { memset(guid,0,sizeof(guid)); }
-+ ~mpb_client_upload_interval_write() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+ // public data
-+ unsigned char guid[16];
-+ char flags; // & 1 = end
-+
-+ void *audio_data;
-+ int audio_data_len; // not encoded in, just used internally
-+};
-+
-+
-+#define MESSAGE_CHAT_MESSAGE 0xC0
-+class mpb_chat_message
-+{
-+ public:
-+ mpb_chat_message() { memset(parms,0,sizeof(parms)); }
-+ ~mpb_chat_message() { }
-+
-+ int parse(Net_Message *msg); // return 0 on success
-+ Net_Message *build();
-+
-+ char *parms[5];
-+
-+ // currently defined client->server commands:
-+ // MSG <text> - sends a message to everybody
-+ // PRIVMSG username <text> - sends a private message to username
-+ // TOPIC <topic> - set server topic (need permissions)
-+
-+ // and server->client commands:
-+ // MSG <username> <text> - a message from username
-+ // PRIVMSG username <text> - a private message from username
-+ // TOPIC <topic> - server topic change
-+};
-+
-+
-+
-+
-+#endif//_MPB_H_
-diff -Naur ninjam-cclient-0.01a/src/netmsg.cpp ninjam/src/netmsg.cpp
---- ninjam-cclient-0.01a/src/netmsg.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/netmsg.cpp 2005-08-30 03:16:06.000000000 +0000
-@@ -0,0 +1,257 @@
-+/*
-+ NINJAM - netmsg.cpp
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This file provides the implementations of the Net_Messsage class, and
-+ Net_Connection class (handles sending and receiving Net_Messages to
-+ a JNetLib JNL_Connection).
-+
-+*/
-+
-+
-+#ifdef _WIN32
-+#include <windows.h>
-+#else
-+#include <stdlib.h>
-+#include <memory.h>
-+#endif
-+
-+#include "netmsg.h"
-+
-+int Net_Message::parseBytesNeeded()
-+{
-+ return get_size()-m_parsepos;
-+}
-+
-+int Net_Message::parseAddBytes(void *data, int len)
-+{
-+ char *p=(char*)get_data();
-+ if (!p) return 0;
-+ if (len > parseBytesNeeded()) len = parseBytesNeeded();
-+ memcpy(p+m_parsepos,data,len);
-+ m_parsepos+=len;
-+ return len;
-+}
-+
-+int Net_Message::parseMessageHeader(void *data, int len) // returns bytes used, if any (or 0 if more data needed) or -1 if invalid
-+{
-+ unsigned char *dp=(unsigned char *)data;
-+ if (len < 5) return 0;
-+
-+ int type=*dp++;
-+
-+ int size = *dp++;
-+ size |= ((int)*dp++)<<8;
-+ size |= ((int)*dp++)<<16;
-+ size |= ((int)*dp++)<<24;
-+ len -= 5;
-+ if (type == MESSAGE_INVALID || size < 0 || size > NET_MESSAGE_MAX_SIZE) return -1;
-+
-+ m_type=type;
-+ set_size(size);
-+
-+ m_parsepos=0;
-+
-+ return 5;
-+}
-+
-+int Net_Message::makeMessageHeader(void *data) // makes message header, data should be at least 16 bytes to be safe
-+{
-+ if (!data) return 0;
-+
-+ unsigned char *dp=(unsigned char *)data;
-+ *dp++ = (unsigned char) m_type;
-+ int size=get_size();
-+ *dp++=size&0xff; size>>=8;
-+ *dp++=size&0xff; size>>=8;
-+ *dp++=size&0xff; size>>=8;
-+ *dp++=size&0xff;
-+
-+ return (dp-(unsigned char *)data);
-+}
-+
-+
-+
-+Net_Message *Net_Connection::Run(int *wantsleep)
-+{
-+ if (!m_con || m_error) return 0;
-+
-+ m_con->run();
-+
-+ time_t now=time(NULL);
-+
-+ if (m_sendq.Available() > 0) m_last_send=now;
-+ else if (now > m_last_send + m_keepalive)
-+ {
-+ Net_Message *keepalive= new Net_Message;
-+ keepalive->set_type(MESSAGE_KEEPALIVE);
-+ keepalive->set_size(0);
-+ Send(keepalive);
-+ m_last_send=now;
-+ }
-+
-+ // handle sending
-+ while (m_con->send_bytes_available()>64 && m_sendq.Available()>0)
-+ {
-+ Net_Message **topofq = (Net_Message **)m_sendq.Get();
-+
-+ if (!topofq) break;
-+ Net_Message *sendm=*topofq;
-+ if (sendm)
-+ {
-+ if (wantsleep) *wantsleep=0;
-+ if (m_msgsendpos<0) // send header
-+ {
-+ char buf[32];
-+ int hdrlen=sendm->makeMessageHeader(buf);
-+ m_con->send_bytes(buf,hdrlen);
-+
-+ m_msgsendpos=0;
-+ }
-+
-+ int sz=sendm->get_size()-m_msgsendpos;
-+ if (sz < 1) // end of message, discard and move to next
-+ {
-+ sendm->releaseRef();
-+ m_sendq.Advance(sizeof(Net_Message*));
-+ m_msgsendpos=-1;
-+ }
-+ else
-+ {
-+ int avail=m_con->send_bytes_available();
-+ if (sz > avail) sz=avail;
-+ if (sz>0)
-+ {
-+ m_con->send_bytes((char*)sendm->get_data()+m_msgsendpos,sz);
-+ m_msgsendpos+=sz;
-+ }
-+ }
-+ }
-+ else
-+ {
-+ m_sendq.Advance(sizeof(Net_Message*));
-+ m_msgsendpos=-1;
-+ }
-+ }
-+
-+ m_sendq.Compact();
-+
-+ Net_Message *retv=0;
-+
-+ // handle receive now
-+ if (!m_recvmsg)
-+ {
-+ m_recvmsg=new Net_Message;
-+ m_recvstate=0;
-+ }
-+
-+ while (!retv && m_con->recv_bytes_available()>0)
-+ {
-+ char buf[8192];
-+ int bufl=m_con->peek_bytes(buf,sizeof(buf));
-+ int a=0;
-+
-+ if (!m_recvstate)
-+ {
-+ a=m_recvmsg->parseMessageHeader(buf,bufl);
-+ if (a<0)
-+ {
-+ m_error=-1;
-+ break;
-+ }
-+ if (a==0) break;
-+ m_recvstate=1;
-+ }
-+ int b2=m_recvmsg->parseAddBytes(buf+a,bufl-a);
-+
-+ m_con->recv_bytes(buf,b2+a); // dump our bytes that we used
-+
-+ if (m_recvmsg->parseBytesNeeded()<1)
-+ {
-+ retv=m_recvmsg;
-+ m_recvmsg=0;
-+ m_recvstate=0;
-+ }
-+ if (wantsleep) *wantsleep=0;
-+ }
-+
-+ m_con->run();
-+
-+
-+ if (retv)
-+ {
-+ m_last_recv=now;
-+ }
-+ else if (now > m_last_recv + m_keepalive*3)
-+ {
-+ m_error=-3;
-+ }
-+
-+ return retv;
-+}
-+
-+int Net_Connection::Send(Net_Message *msg)
-+{
-+ if (msg)
-+ {
-+ msg->addRef();
-+ if (m_sendq.GetSize() < NET_CON_MAX_MESSAGES*(int)sizeof(Net_Message *))
-+ m_sendq.Add(&msg,sizeof(Net_Message *));
-+ else
-+ {
-+ m_error=-2;
-+ msg->releaseRef(); // todo: debug message to log overrun error
-+ return -1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+int Net_Connection::GetStatus()
-+{
-+ if (m_error) return m_error;
-+ return !m_con || m_con->get_state()<JNL_Connection::STATE_RESOLVING || m_con->get_state()>=JNL_Connection::STATE_CLOSING; // 1 if disconnected somehow
-+}
-+
-+Net_Connection::~Net_Connection()
-+{
-+ Net_Message **p=(Net_Message **)m_sendq.Get();
-+ if (p)
-+ {
-+ int n=m_sendq.Available()/sizeof(Net_Message *);
-+ while (n-->0)
-+ {
-+ (*p)->releaseRef();
-+ p++;
-+ }
-+ m_sendq.Advance(m_sendq.Available());
-+
-+ }
-+
-+ delete m_con;
-+ delete m_recvmsg;
-+
-+}
-+
-+
-+void Net_Connection::Kill(int quick)
-+{
-+ m_con->close();
-+}
-diff -Naur ninjam-cclient-0.01a/src/netmsg.h ninjam/src/netmsg.h
---- ninjam-cclient-0.01a/src/netmsg.h 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/netmsg.h 2005-08-30 03:16:06.000000000 +0000
-@@ -0,0 +1,129 @@
-+/*
-+ NINJAM - netmsg.h
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This header provides the declarations for the Net_Messsage class, and
-+ Net_Connection class (handles sending and receiving Net_Messages to
-+ a JNetLib JNL_Connection).
-+*/
-+
-+
-+
-+#ifndef _NETMSG_H_
-+#define _NETMSG_H_
-+
-+#include "../WDL/queue.h"
-+#include "../WDL/jnetlib/jnetlib.h"
-+
-+#define NET_MESSAGE_MAX_SIZE 16384
-+
-+#define NET_CON_MAX_MESSAGES 512
-+
-+#define MESSAGE_KEEPALIVE 0xfd
-+#define MESSAGE_EXTENDED 0xfe
-+#define MESSAGE_INVALID 0xff
-+
-+#define NET_CON_KEEPALIVE_RATE 3
-+
-+
-+class Net_Message
-+{
-+ public:
-+ Net_Message() : m_parsepos(0), m_refcnt(0), m_type(MESSAGE_INVALID)
-+ {
-+ }
-+ ~Net_Message()
-+ {
-+ }
-+
-+
-+ void set_type(int type) { m_type=type; }
-+ int get_type() { return m_type; }
-+
-+ void set_size(int newsize) { m_hb.Resize(newsize); }
-+ int get_size() { return m_hb.GetSize(); }
-+
-+ void *get_data() { return m_hb.Get(); }
-+
-+
-+ int parseMessageHeader(void *data, int len); // returns bytes used, if any (or 0 if more data needed), or -1 if invalid
-+ int parseBytesNeeded();
-+ int parseAddBytes(void *data, int len); // returns bytes actually added
-+
-+ int makeMessageHeader(void *data); // makes message header, returns length. data should be at least 16 bytes to be safe
-+
-+
-+ void addRef() { ++m_refcnt; }
-+ void releaseRef() { if (--m_refcnt < 1) delete this; }
-+
-+ private:
-+ int m_parsepos;
-+ int m_refcnt;
-+ int m_type;
-+ WDL_HeapBuf m_hb;
-+};
-+
-+
-+class Net_Connection
-+{
-+ public:
-+ Net_Connection() : m_error(0),m_msgsendpos(-1), m_recvstate(0),m_recvmsg(0),m_con(0)
-+ {
-+ SetKeepAlive(0);
-+ }
-+ ~Net_Connection();
-+
-+ void attach(JNL_Connection *con)
-+ {
-+ m_con=con;
-+ }
-+
-+ Net_Message *Run(int *wantsleep=0);
-+ int Send(Net_Message *msg); // -1 on error, i.e. queue full
-+ int GetStatus(); // returns <0 on error, 0 on normal, 1 on disconnect
-+ JNL_Connection *GetConnection() { return m_con; }
-+
-+ void SetKeepAlive(int interval)
-+ {
-+ m_keepalive=interval?interval:NET_CON_KEEPALIVE_RATE;
-+ m_last_send=m_last_recv=time(NULL);
-+ }
-+
-+ void Kill(int quick=0);
-+
-+ private:
-+ int m_error;
-+
-+ int m_keepalive;
-+ int m_msgsendpos;
-+
-+ time_t m_last_send, m_last_recv;
-+
-+ int m_recvstate;
-+ Net_Message *m_recvmsg;
-+
-+ JNL_Connection *m_con;
-+ WDL_Queue m_sendq;
-+
-+
-+};
-+
-+
-+#endif
-diff -Naur ninjam-cclient-0.01a/src/njclient.cpp ninjam/src/njclient.cpp
---- ninjam-cclient-0.01a/src/njclient.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/njclient.cpp 2005-08-30 03:16:06.000000000 +0000
-@@ -0,0 +1,2142 @@
-+/*
-+ NINJAM - njclient.cpp
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ For a full description of everything here, see njclient.h
-+*/
-+
-+
-+#include <math.h>
-+#include <stdio.h>
-+#include <stdarg.h>
-+#include "njclient.h"
-+#include "mpb.h"
-+#include "../WDL/pcmfmtcvt.h"
-+#include "../WDL/wavwrite.h"
-+
-+
-+
-+// todo: make an interface base class for vorbis enc/dec
-+#define VorbisEncoder I_NJEncoder
-+#define VorbisDecoder I_NJDecoder
-+#define NJ_ENCODER_FMT_TYPE MAKE_NJ_FOURCC('O','G','G','v')
-+#include "../WDL/vorbisencdec.h"
-+#undef VorbisEncoder
-+#undef VorbisDecoder
-+
-+
-+#define MAKE_NJ_FOURCC(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24))
-+
-+class DecodeState
-+{
-+ public:
-+ DecodeState() : decode_fp(0), decode_codec(0), dump_samples(0),
-+ decode_samplesout(0), resample_state(0.0), decode_peak_vol(0.0)
-+ {
-+ memset(guid,0,sizeof(guid));
-+ }
-+ ~DecodeState()
-+ {
-+ delete decode_codec;
-+ decode_codec=0;
-+ if (decode_fp) fclose(decode_fp);
-+ decode_fp=0;
-+
-+ if (delete_on_delete.Get()[0])
-+ {
-+#ifdef _WIN32
-+ DeleteFile(delete_on_delete.Get());
-+#else
-+ unlink(delete_on_delete.Get());
-+#endif
-+ }
-+ }
-+
-+ unsigned char guid[16];
-+ double decode_peak_vol;
-+
-+ WDL_String delete_on_delete;
-+
-+ FILE *decode_fp;
-+ I_NJDecoder *decode_codec;
-+ int decode_samplesout;
-+ int dump_samples;
-+ double resample_state;
-+
-+};
-+
-+
-+class RemoteUser_Channel
-+{
-+ public:
-+ RemoteUser_Channel();
-+ ~RemoteUser_Channel();
-+
-+ float volume, pan;
-+
-+ WDL_String name;
-+
-+ // decode/mixer state, used by mixer
-+ DecodeState *ds;
-+ DecodeState *next_ds[2]; // prepared by main thread, for audio thread
-+
-+};
-+
-+class RemoteUser
-+{
-+public:
-+ RemoteUser() : muted(0), volume(1.0f), pan(0.0f), submask(0), mutedmask(0), solomask(0), chanpresentmask(0) { }
-+ ~RemoteUser() { }
-+
-+ bool muted;
-+ float volume;
-+ float pan;
-+ WDL_String name;
-+ int submask;
-+ int chanpresentmask;
-+ int mutedmask;
-+ int solomask;
-+ RemoteUser_Channel channels[MAX_USER_CHANNELS];
-+};
-+
-+
-+class RemoteDownload
-+{
-+public:
-+ RemoteDownload();
-+ ~RemoteDownload();
-+
-+ void Close();
-+ void Open(NJClient *parent, unsigned int fourcc);
-+ void Write(void *buf, int len);
-+ void startPlaying(int force=0); // call this with 1 to make sure it gets played ASAP, or let RemoteDownload call it automatically
-+
-+ time_t last_time;
-+ unsigned char guid[16];
-+
-+ int chidx;
-+ WDL_String username;
-+ int playtime;
-+
-+private:
-+ unsigned int m_fourcc;
-+ NJClient *m_parent;
-+ FILE *fp;
-+};
-+
-+
-+
-+class BufferQueue
-+{
-+ public:
-+ BufferQueue() { }
-+ ~BufferQueue()
-+ {
-+ Clear();
-+ }
-+
-+ void AddBlock(float *samples, int len, float *samples2=NULL);
-+ int GetBlock(WDL_HeapBuf **b); // return 0 if got one, 1 if none avail
-+ void DisposeBlock(WDL_HeapBuf *b);
-+
-+ void Clear()
-+ {
-+ int x;
-+ for (x = 0; x < m_emptybufs.GetSize(); x ++)
-+ delete m_emptybufs.Get(x);
-+ m_emptybufs.Empty();
-+ int l=m_samplequeue.Available()/4;
-+ WDL_HeapBuf **bufs=(WDL_HeapBuf **)m_samplequeue.Get();
-+ if (bufs) while (l--)
-+ {
-+ if ((int)*bufs != 0 && (int)*bufs != -1) delete *bufs;
-+ bufs++;
-+ }
-+ m_samplequeue.Advance(m_samplequeue.Available());
-+ m_samplequeue.Compact();
-+ }
-+
-+ private:
-+ WDL_Queue m_samplequeue; // a list of pointers, with NULL to define spaces
-+ WDL_PtrList<WDL_HeapBuf> m_emptybufs;
-+ WDL_Mutex m_cs;
-+};
-+
-+
-+class Local_Channel
-+{
-+public:
-+ Local_Channel();
-+ ~Local_Channel();
-+
-+ int channel_idx;
-+
-+ int src_channel; // 0 or 1
-+ int bitrate;
-+
-+ float volume;
-+ float pan;
-+ bool muted;
-+ bool solo;
-+
-+ //?
-+ // mode flag. 0=silence, 1=broadcasting
-+ bool broadcasting; //takes effect next loop
-+
-+
-+
-+ // internal state. should ONLY be used by the audio thread.
-+ bool bcast_active;
-+
-+
-+ void (*cbf)(float *, int ns, void *);
-+ void *cbf_inst;
-+
-+ BufferQueue m_bq;
-+
-+ double decode_peak_vol;
-+ bool m_need_header;
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ I_NJEncoder *m_enc;
-+ int m_enc_bitrate_used;
-+ Net_Message *m_enc_header_needsend;
-+#endif
-+
-+ WDL_String name;
-+ RemoteDownload m_curwritefile;
-+ WaveWriter *m_wavewritefile;
-+
-+ //DecodeState too, eventually
-+};
-+
-+
-+
-+
-+
-+
-+
-+#define MIN_ENC_BLOCKSIZE 2048
-+#define MAX_ENC_BLOCKSIZE (8192+1024)
-+
-+
-+#define NJ_PORT 2049
-+
-+static unsigned char zero_guid[16];
-+
-+
-+static void guidtostr(unsigned char *guid, char *str)
-+{
-+ int x;
-+ for (x = 0; x < 16; x ++) wsprintf(str+x*2,"%02x",guid[x]);
-+}
-+static char *guidtostr_tmp(unsigned char *guid)
-+{
-+ static char tmp[64];
-+ guidtostr(guid,tmp);
-+ return tmp;
-+}
-+
-+
-+static int is_type_char_valid(int c)
-+{
-+ c&=0xff;
-+ return (c >= 'a' && c <= 'z') ||
-+ (c >= 'A' && c <= 'Z') ||
-+ (c >= '0' && c <= '9') ||
-+ c == ' ' || c == '-' ||
-+ c == '.' || c == '_';
-+}
-+
-+static int is_type_valid(unsigned int t)
-+{
-+ return (t&0xff) != ' ' &&
-+ is_type_char_valid(t>>24) &&
-+ is_type_char_valid(t>>16) &&
-+ is_type_char_valid(t>>8) &&
-+ is_type_char_valid(t);
-+}
-+
-+
-+static void type_to_string(unsigned int t, char *out)
-+{
-+ if (is_type_valid(t))
-+ {
-+ out[0]=(t)&0xff;
-+ out[1]=(t>>8)&0xff;
-+ out[2]=(t>>16)&0xff;
-+ out[3]=' ';//(t>>24)&0xff;
-+ out[4]=0;
-+ int x=3;
-+ while (out[x]==' ' && x > 0) out[x--]=0;
-+ }
-+ else *out=0;
-+}
-+
-+static unsigned int string_to_type(char *in)
-+{
-+ int n;
-+ unsigned int ret=*in;
-+ if (*in == ' ' || !is_type_char_valid(*in)) return 0;
-+ in++;
-+ for (n = 0; n < 3; n ++)
-+ {
-+ if (!is_type_char_valid(*in)) break;
-+ ret|=(*in<<(8+8*n));
-+ in++;
-+ }
-+ if (*in) return 0;
-+ return ret;
-+}
-+
-+
-+void NJClient::makeFilenameFromGuid(WDL_String *s, unsigned char *guid)
-+{
-+ char buf[256];
-+ guidtostr(guid,buf);
-+
-+ s->Set(m_workdir.Get());
-+#ifdef _WIN32
-+ char tmp[3]={buf[0],'\\',0};
-+#else
-+ char tmp[3]={buf[0],'/',0};
-+#endif
-+ s->Append(tmp);
-+ s->Append(buf);
-+}
-+
-+
-+
-+
-+NJClient::NJClient()
-+{
-+ m_wavebq=new BufferQueue;
-+ m_userinfochange=0;
-+ m_loopcnt=0;
-+ m_srate=48000;
-+#ifdef _WIN32
-+ DWORD v=GetTickCount();
-+ WDL_RNG_addentropy(&v,sizeof(v));
-+ v=(DWORD)time(NULL);
-+ WDL_RNG_addentropy(&v,sizeof(v));
-+#else
-+ time_t v=time(NULL);
-+ WDL_RNG_addentropy(&v,sizeof(v));
-+#endif
-+
-+ config_autosubscribe=1;
-+ config_savelocalaudio=0;
-+ config_metronome=0.5f;
-+ config_metronome_pan=0.0f;
-+ config_metronome_mute=false;
-+ config_debug_level=0;
-+ config_mastervolume=1.0f;
-+ config_masterpan=0.0f;
-+ config_mastermute=false;
-+ config_play_prebuffer=8192;
-+
-+
-+ LicenseAgreement_User32=0;
-+ LicenseAgreementCallback=0;
-+ ChatMessage_Callback=0;
-+ ChatMessage_User32=0;
-+ ChannelMixer=0;
-+ ChannelMixer_User32=0;
-+
-+ waveWrite=0;
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ m_oggWrite=0;
-+ m_oggComp=0;
-+#endif
-+ m_logFile=0;
-+
-+ m_issoloactive=0;
-+ m_netcon=0;
-+
-+ _reinit();
-+
-+ m_session_pos_ms=m_session_pos_samples=0;
-+}
-+
-+void NJClient::_reinit()
-+{
-+ m_max_localch=MAX_LOCAL_CHANNELS;
-+ output_peaklevel=0.0;
-+
-+ m_connection_keepalive=0;
-+ m_status=-1;
-+
-+ m_in_auth=0;
-+
-+ m_bpm=120;
-+ m_bpi=32;
-+
-+ m_beatinfo_updated=1;
-+
-+ m_audio_enable=0;
-+
-+ m_active_bpm=120;
-+ m_active_bpi=32;
-+ m_interval_length=1000;
-+ m_interval_pos=-1;
-+ m_metronome_pos=0.0;
-+ m_metronome_state=0;
-+ m_metronome_tmp=0;
-+ m_metronome_interval=0;
-+
-+ m_issoloactive&=~1;
-+
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize(); x ++)
-+ m_locchannels.Get(x)->decode_peak_vol=0.0f;
-+
-+}
-+
-+
-+void NJClient::writeLog(char *fmt, ...)
-+{
-+ if (m_logFile)
-+ {
-+ va_list ap;
-+ va_start(ap,fmt);
-+
-+ m_log_cs.Enter();
-+ if (m_logFile) vfprintf(m_logFile,fmt,ap);
-+ m_log_cs.Leave();
-+
-+ va_end(ap);
-+
-+ }
-+
-+
-+}
-+
-+void NJClient::SetLogFile(char *name)
-+{
-+ m_log_cs.Enter();
-+ if (m_logFile) fclose(m_logFile);
-+ m_logFile=0;
-+ if (name && *name)
-+ {
-+ if (!strstr(name,"\\") && !strstr(name,"/") && !strstr(name,":"))
-+ {
-+ WDL_String s(m_workdir.Get());
-+ s.Append(name);
-+ m_logFile=fopen(s.Get(),"a+t");
-+ }
-+ else
-+ m_logFile=fopen(name,"a+t");
-+ }
-+ m_log_cs.Leave();
-+}
-+
-+
-+NJClient::~NJClient()
-+{
-+ delete m_netcon;
-+ m_netcon=0;
-+
-+ delete waveWrite;
-+ SetOggOutFile(NULL,0,0);
-+
-+ if (m_logFile)
-+ {
-+ writeLog("end\n");
-+ fclose(m_logFile);
-+ m_logFile=0;
-+ }
-+
-+ int x;
-+ for (x = 0; x < m_remoteusers.GetSize(); x ++) delete m_remoteusers.Get(x);
-+ m_remoteusers.Empty();
-+ for (x = 0; x < m_downloads.GetSize(); x ++) delete m_downloads.Get(x);
-+ m_downloads.Empty();
-+ for (x = 0; x < m_locchannels.GetSize(); x ++) delete m_locchannels.Get(x);
-+ m_locchannels.Empty();
-+
-+ delete m_wavebq;
-+}
-+
-+
-+void NJClient::updateBPMinfo(int bpm, int bpi)
-+{
-+ m_misc_cs.Enter();
-+ m_bpm=bpm;
-+ m_bpi=bpi;
-+ m_beatinfo_updated=1;
-+ m_misc_cs.Leave();
-+}
-+
-+
-+void NJClient::GetPosition(int *pos, int *length) // positions in samples
-+{
-+ if (length) *length=m_interval_length;
-+ if (pos && (*pos=m_interval_pos)<0) *pos=0;
-+}
-+
-+unsigned int NJClient::GetSessionPosition()// returns milliseconds
-+{
-+ unsigned int a=m_session_pos_ms;
-+ if (m_srate)
-+ a+=(m_session_pos_samples*1000)/m_srate;
-+ return a;
-+}
-+
-+void NJClient::AudioProc(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate)
-+{
-+ m_srate=srate;
-+ // zero output
-+ int x;
-+ for (x = 0; x < outnch; x ++) memset(outbuf[x],0,sizeof(float)*len);
-+
-+ if (!m_audio_enable)
-+ {
-+ process_samples(inbuf,innch,outbuf,outnch,len,srate,0,1);
-+ return;
-+ }
-+
-+ if (srate>0)
-+ {
-+ unsigned int spl=m_session_pos_samples;
-+ unsigned int sec=m_session_pos_ms;
-+
-+ spl += len;
-+ if (spl >= (unsigned int)srate)
-+ {
-+ sec += (spl/srate)*1000;
-+ spl %= srate;
-+ }
-+ // writing these both like this reduces the chance that the
-+ // main thread will read them and get a mix. still possible, tho,
-+ // but super unlikely
-+ m_session_pos_samples=spl;
-+ m_session_pos_ms=sec;
-+ }
-+
-+
-+
-+ int offs=0;
-+
-+ while (len > 0)
-+ {
-+ int x=m_interval_length-m_interval_pos;
-+ if (!x || m_interval_pos < 0)
-+ {
-+ m_misc_cs.Enter();
-+ if (m_beatinfo_updated)
-+ {
-+ double v=(double)m_bpm*(1.0/60.0);
-+ // beats per second
-+
-+ // (beats/interval) / (beats/sec)
-+ v = (double) m_bpi / v;
-+
-+ // seconds/interval
-+
-+ // samples/interval
-+ v *= (double) srate;
-+
-+ m_beatinfo_updated=0;
-+ m_interval_length = (int)v;
-+ //m_interval_length-=m_interval_length%1152;//hack
-+ m_active_bpm=m_bpm;
-+ m_active_bpi=m_bpi;
-+ m_metronome_interval=(int) ((double)m_interval_length / (double)m_active_bpi);
-+ }
-+ m_misc_cs.Leave();
-+
-+ // new buffer time
-+ on_new_interval();
-+
-+ m_interval_pos=0;
-+ x=m_interval_length;
-+ }
-+
-+ if (x > len) x=len;
-+
-+ process_samples(inbuf,innch,outbuf,outnch,x,srate,offs);
-+
-+ m_interval_pos+=x;
-+ offs += x;
-+ len -= x;
-+ }
-+
-+}
-+
-+
-+void NJClient::Disconnect()
-+{
-+ m_errstr.Set("");
-+ m_host.Set("");
-+ m_user.Set("");
-+ m_pass.Set("");
-+ delete m_netcon;
-+ m_netcon=0;
-+
-+ int x;
-+ for (x=0;x<m_remoteusers.GetSize(); x++) delete m_remoteusers.Get(x);
-+ m_remoteusers.Empty();
-+ if (x) m_userinfochange=1; // if we removed users, notify parent
-+
-+ for (x = 0; x < m_downloads.GetSize(); x ++) delete m_downloads.Get(x);
-+
-+
-+ for (x = 0; x < m_locchannels.GetSize(); x ++)
-+ {
-+ Local_Channel *c=m_locchannels.Get(x);
-+ delete c->m_wavewritefile;
-+ c->m_wavewritefile=0;
-+ c->m_curwritefile.Close();
-+
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ delete c->m_enc;
-+ c->m_enc=0;
-+ delete c->m_enc_header_needsend;
-+ c->m_enc_header_needsend=0;
-+#endif
-+
-+ c->m_bq.Clear();
-+ }
-+ m_downloads.Empty();
-+
-+ m_wavebq->Clear();
-+
-+ _reinit();
-+}
-+
-+void NJClient::Connect(char *host, char *user, char *pass)
-+{
-+ Disconnect();
-+
-+ m_session_pos_ms=m_session_pos_samples=0;
-+
-+ m_host.Set(host);
-+ m_user.Set(user);
-+ m_pass.Set(pass);
-+
-+ WDL_String tmp(m_host.Get());
-+ int port=NJ_PORT;
-+ char *p=strstr(tmp.Get(),":");
-+ if (p)
-+ {
-+ *p=0;
-+ port=atoi(++p);
-+ if (!port) port=NJ_PORT;
-+ }
-+ JNL_Connection *c=new JNL_Connection(JNL_CONNECTION_AUTODNS,65536,65536);
-+ c->connect(tmp.Get(),port);
-+ m_netcon = new Net_Connection;
-+ m_netcon->attach(c);
-+
-+ m_status=0;
-+}
-+
-+int NJClient::GetStatus()
-+{
-+ if (!m_status || m_status == -1) return NJC_STATUS_PRECONNECT;
-+ if (m_status == 1000) return NJC_STATUS_CANTCONNECT;
-+ if (m_status == 1001) return NJC_STATUS_INVALIDAUTH;
-+ if (m_status == 1002) return NJC_STATUS_DISCONNECTED;
-+
-+ return NJC_STATUS_OK;
-+}
-+
-+
-+int NJClient::Run() // nonzero if sleep ok
-+{
-+ WDL_HeapBuf *p=0;
-+ while (!m_wavebq->GetBlock(&p))
-+ {
-+ if (p)
-+ {
-+ float *f=(float*)p->Get();
-+ int hl=p->GetSize()/(2*sizeof(float));
-+ float *outbuf[2]={f,f+hl};
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ if (m_oggWrite&&m_oggComp)
-+ {
-+ m_oggComp->Encode(f,hl,1,hl);
-+ if (m_oggComp->outqueue.Available())
-+ {
-+ fwrite((char *)m_oggComp->outqueue.Get(),1,m_oggComp->outqueue.Available(),m_oggWrite);
-+ m_oggComp->outqueue.Advance(m_oggComp->outqueue.Available());
-+ m_oggComp->outqueue.Compact();
-+ }
-+ }
-+#endif
-+ if (waveWrite)
-+ {
-+ waveWrite->WriteFloatsNI(outbuf,0,hl);
-+ }
-+ m_wavebq->DisposeBlock(p);
-+ }
-+ }
-+//
-+ int wantsleep=1;
-+
-+ if (m_netcon)
-+ {
-+ Net_Message *msg=m_netcon->Run(&wantsleep);
-+ if (!msg)
-+ {
-+ if (m_netcon->GetStatus())
-+ {
-+ m_audio_enable=0;
-+ if (m_in_auth) m_status=1001;
-+ if (m_status > 0 && m_status < 1000) m_status=1002;
-+ if (m_status == 0) m_status=1000;
-+ return 1;
-+ }
-+ }
-+ else
-+ {
-+ msg->addRef();
-+
-+ switch (msg->get_type())
-+ {
-+ case MESSAGE_SERVER_AUTH_CHALLENGE:
-+ {
-+ mpb_server_auth_challenge cha;
-+ if (!cha.parse(msg))
-+ {
-+ if (cha.protocol_version < PROTO_VER_MIN || cha.protocol_version >= PROTO_VER_MAX)
-+ {
-+ m_errstr.Set("server is incorrect protocol version");
-+ m_status = 1001;
-+ m_netcon->Kill();
-+ return 0;
-+ }
-+
-+ mpb_client_auth_user repl;
-+ repl.username=m_user.Get();
-+ repl.client_version=PROTO_VER_CUR; // client version number
-+
-+ m_connection_keepalive=(cha.server_caps>>8)&0xff;
-+
-+// printf("Got keepalive of %d\n",m_connection_keepalive);
-+
-+ if (cha.license_agreement)
-+ {
-+ m_netcon->SetKeepAlive(45);
-+ if (LicenseAgreementCallback && LicenseAgreementCallback(LicenseAgreement_User32,cha.license_agreement))
-+ {
-+ repl.client_caps|=1;
-+ }
-+ }
-+ m_netcon->SetKeepAlive(m_connection_keepalive);
-+
-+ WDL_SHA1 tmp;
-+ tmp.add(m_user.Get(),strlen(m_user.Get()));
-+ tmp.add(":",1);
-+ tmp.add(m_pass.Get(),strlen(m_pass.Get()));
-+ tmp.result(repl.passhash);
-+
-+ tmp.reset(); // new auth method is SHA1(SHA1(user:pass)+challenge)
-+ tmp.add(repl.passhash,sizeof(repl.passhash));
-+ tmp.add(cha.challenge,sizeof(cha.challenge));
-+ tmp.result(repl.passhash);
-+
-+ m_netcon->Send(repl.build());
-+
-+ m_in_auth=1;
-+ }
-+ }
-+ break;
-+ case MESSAGE_SERVER_AUTH_REPLY:
-+ {
-+ mpb_server_auth_reply ar;
-+ if (!ar.parse(msg))
-+ {
-+ if (ar.flag) // send our channel information
-+ {
-+ mpb_client_set_channel_info sci;
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize(); x ++)
-+ {
-+ Local_Channel *ch=m_locchannels.Get(x);
-+ sci.build_add_rec(ch->name.Get(),0,0,0);
-+ }
-+ m_netcon->Send(sci.build());
-+ m_status=2;
-+ m_in_auth=0;
-+ m_max_localch=ar.maxchan;
-+ if (ar.errmsg)
-+ m_user.Set(ar.errmsg); // server gave us an updated name
-+ }
-+ else
-+ {
-+ if (ar.errmsg)
-+ {
-+ m_errstr.Set(ar.errmsg);
-+ }
-+ m_status = 1001;
-+ m_netcon->Kill();
-+ }
-+ }
-+ }
-+ break;
-+ case MESSAGE_SERVER_CONFIG_CHANGE_NOTIFY:
-+ {
-+ mpb_server_config_change_notify ccn;
-+ if (!ccn.parse(msg))
-+ {
-+ updateBPMinfo(ccn.beats_minute,ccn.beats_interval);
-+ m_audio_enable=1;
-+ }
-+ }
-+
-+ break;
-+ case MESSAGE_SERVER_USERINFO_CHANGE_NOTIFY:
-+ {
-+ mpb_server_userinfo_change_notify ucn;
-+ if (!ucn.parse(msg))
-+ {
-+ int offs=0;
-+ int a=0, cid=0, p=0,f=0;
-+ short v=0;
-+ char *un=0,*chn=0;
-+ while ((offs=ucn.parse_get_rec(offs,&a,&cid,&v,&p,&f,&un,&chn))>0)
-+ {
-+ if (!un) un="";
-+ if (!chn) chn="";
-+
-+ m_userinfochange=1;
-+
-+ int x;
-+ // todo: per-user autosubscribe option, or callback
-+ // todo: have volume/pan settings here go into defaults for the channel. or not, kinda think it's pointless
-+ if (cid >= 0 && cid < MAX_USER_CHANNELS)
-+ {
-+ RemoteUser *theuser;
-+ for (x = 0; x < m_remoteusers.GetSize() && strcmp((theuser=m_remoteusers.Get(x))->name.Get(),un); x ++);
-+
-+ // printf("user %s, channel %d \"%s\": %s v:%d.%ddB p:%d flag=%d\n",un,cid,chn,a?"active":"inactive",(int)v/10,abs((int)v)%10,p,f);
-+
-+
-+ m_users_cs.Enter();
-+ if (a)
-+ {
-+ if (x == m_remoteusers.GetSize())
-+ {
-+ theuser=new RemoteUser;
-+ theuser->name.Set(un);
-+ m_remoteusers.Add(theuser);
-+ }
-+
-+ theuser->channels[cid].name.Set(chn);
-+ theuser->chanpresentmask |= 1<<cid;
-+
-+
-+ if (config_autosubscribe)
-+ {
-+ theuser->submask |= 1<<cid;
-+ mpb_client_set_usermask su;
-+ su.build_add_rec(un,theuser->submask);
-+ m_netcon->Send(su.build());
-+ }
-+ }
-+ else
-+ {
-+ if (x < m_remoteusers.GetSize())
-+ {
-+ theuser->channels[cid].name.Set("");
-+ theuser->chanpresentmask &= ~(1<<cid);
-+ theuser->submask &= ~(1<<cid);
-+
-+ int chksolo=theuser->solomask == (1<<cid);
-+ theuser->solomask &= ~(1<<cid);
-+
-+ delete theuser->channels[cid].ds;
-+ delete theuser->channels[cid].next_ds[0];
-+ delete theuser->channels[cid].next_ds[1];
-+ theuser->channels[cid].ds=0;
-+ theuser->channels[cid].next_ds[0]=0;
-+ theuser->channels[cid].next_ds[1]=0;
-+
-+ if (!theuser->chanpresentmask) // user no longer exists, it seems
-+ {
-+ chksolo=1;
-+ delete theuser;
-+ m_remoteusers.Delete(x);
-+ }
-+
-+ if (chksolo)
-+ {
-+ int i;
-+ for (i = 0; i < m_remoteusers.GetSize() && !m_remoteusers.Get(i)->solomask; i ++);
-+
-+ if (i < m_remoteusers.GetSize()) m_issoloactive|=1;
-+ else m_issoloactive&=~1;
-+ }
-+ }
-+ }
-+ m_users_cs.Leave();
-+ }
-+ }
-+ }
-+ }
-+ break;
-+ case MESSAGE_SERVER_DOWNLOAD_INTERVAL_BEGIN:
-+ {
-+ mpb_server_download_interval_begin dib;
-+ if (!dib.parse(msg) && dib.username)
-+ {
-+ int x;
-+ RemoteUser *theuser;
-+ for (x = 0; x < m_remoteusers.GetSize() && strcmp((theuser=m_remoteusers.Get(x))->name.Get(),dib.username); x ++);
-+ if (x < m_remoteusers.GetSize() && dib.chidx >= 0 && dib.chidx < MAX_USER_CHANNELS)
-+ {
-+ //printf("Getting interval for %s, channel %d\n",dib.username,dib.chidx);
-+ if (!memcmp(dib.guid,zero_guid,sizeof(zero_guid)))
-+ {
-+ m_users_cs.Enter();
-+ int useidx=!!theuser->channels[dib.chidx].next_ds[0];
-+ DecodeState *tmp=theuser->channels[dib.chidx].next_ds[useidx];
-+ theuser->channels[dib.chidx].next_ds[useidx]=0;
-+ m_users_cs.Leave();
-+ delete tmp;
-+ }
-+ else if (dib.fourcc) // download coming
-+ {
-+ if (config_debug_level>1) printf("RECV BLOCK %s\n",guidtostr_tmp(dib.guid));
-+ RemoteDownload *ds=new RemoteDownload;
-+ memcpy(ds->guid,dib.guid,sizeof(ds->guid));
-+ ds->Open(this,dib.fourcc);
-+
-+ ds->playtime=config_play_prebuffer;
-+ ds->chidx=dib.chidx;
-+ ds->username.Set(dib.username);
-+
-+ m_downloads.Add(ds);
-+ }
-+ else
-+ {
-+ DecodeState *tmp=start_decode(dib.guid);
-+ m_users_cs.Enter();
-+ int useidx=!!theuser->channels[dib.chidx].next_ds[0];
-+ DecodeState *t2=theuser->channels[dib.chidx].next_ds[useidx];
-+ theuser->channels[dib.chidx].next_ds[useidx]=tmp;
-+ m_users_cs.Leave();
-+ delete t2;
-+ }
-+
-+ }
-+ }
-+ }
-+ break;
-+ case MESSAGE_SERVER_DOWNLOAD_INTERVAL_WRITE:
-+ {
-+ mpb_server_download_interval_write diw;
-+ if (!diw.parse(msg))
-+ {
-+ time_t now;
-+ time(&now);
-+ int x;
-+ for (x = 0; x < m_downloads.GetSize(); x ++)
-+ {
-+ RemoteDownload *ds=m_downloads.Get(x);
-+ if (ds)
-+ {
-+ if (!memcmp(ds->guid,diw.guid,sizeof(ds->guid)))
-+ {
-+ if (config_debug_level>1) printf("RECV BLOCK DATA %s%s %d bytes\n",guidtostr_tmp(diw.guid),diw.flags&1?":end":"",diw.audio_data_len);
-+
-+ ds->last_time=now;
-+ if (diw.audio_data_len > 0 && diw.audio_data)
-+ {
-+ ds->Write(diw.audio_data,diw.audio_data_len);
-+ }
-+ if (diw.flags & 1)
-+ {
-+ delete ds;
-+ m_downloads.Delete(x);
-+ }
-+ break;
-+ }
-+
-+ if (now - ds->last_time > DOWNLOAD_TIMEOUT)
-+ {
-+ ds->chidx=-1;
-+ delete ds;
-+ m_downloads.Delete(x--);
-+ }
-+ }
-+ }
-+ }
-+ }
-+ break;
-+ case MESSAGE_CHAT_MESSAGE:
-+ if (ChatMessage_Callback)
-+ {
-+ mpb_chat_message foo;
-+ if (!foo.parse(msg))
-+ {
-+ ChatMessage_Callback(ChatMessage_User32,this,foo.parms,sizeof(foo.parms)/sizeof(foo.parms[0]));
-+ }
-+ }
-+ break;
-+ default:
-+ //printf("Got unknown message %02X\n",msg->get_type());
-+ break;
-+ }
-+
-+ msg->releaseRef();
-+ }
-+ }
-+
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ int u;
-+ for (u = 0; u < m_locchannels.GetSize(); u ++)
-+ {
-+ Local_Channel *lc=m_locchannels.Get(u);
-+ WDL_HeapBuf *p=0;
-+ while (!lc->m_bq.GetBlock(&p))
-+ {
-+ wantsleep=0;
-+ if (u >= m_max_localch)
-+ {
-+ if (p && (int)p != -1)
-+ lc->m_bq.DisposeBlock(p);
-+ p=0;
-+ continue;
-+ }
-+
-+ if ((int)p == -1)
-+ {
-+ mpb_client_upload_interval_begin cuib;
-+ cuib.chidx=lc->channel_idx;
-+ memset(cuib.guid,0,sizeof(cuib.guid));
-+ memset(lc->m_curwritefile.guid,0,sizeof(lc->m_curwritefile.guid));
-+ cuib.fourcc=0;
-+ cuib.estsize=0;
-+ m_netcon->Send(cuib.build());
-+ p=0;
-+ }
-+ else if (p)
-+ {
-+ // encode data
-+ if (!lc->m_enc)
-+ {
-+ lc->m_enc = new I_NJEncoder(m_srate,1,lc->m_enc_bitrate_used = lc->bitrate,WDL_RNG_int32());
-+ }
-+
-+ if (lc->m_need_header)
-+ {
-+ lc->m_need_header=false;
-+ {
-+ WDL_RNG_bytes(lc->m_curwritefile.guid,sizeof(lc->m_curwritefile.guid));
-+ char guidstr[64];
-+ guidtostr(lc->m_curwritefile.guid,guidstr);
-+ writeLog("local %s %d\n",guidstr,lc->channel_idx);
-+ if (config_savelocalaudio>0)
-+ {
-+ lc->m_curwritefile.Open(this,NJ_ENCODER_FMT_TYPE);
-+ if (lc->m_wavewritefile) delete lc->m_wavewritefile;
-+ lc->m_wavewritefile=0;
-+ if (config_savelocalaudio>1)
-+ {
-+ WDL_String fn;
-+
-+ fn.Set(m_workdir.Get());
-+ #ifdef _WIN32
-+ char tmp[3]={guidstr[0],'\\',0};
-+ #else
-+ char tmp[3]={guidstr[0],'/',0};
-+ #endif
-+ fn.Append(tmp);
-+ fn.Append(guidstr);
-+ fn.Append(".wav");
-+
-+ lc->m_wavewritefile=new WaveWriter(fn.Get(),24,1,m_srate);
-+ }
-+ }
-+
-+ mpb_client_upload_interval_begin cuib;
-+ cuib.chidx=lc->channel_idx;
-+ memcpy(cuib.guid,lc->m_curwritefile.guid,sizeof(cuib.guid));
-+ cuib.fourcc=NJ_ENCODER_FMT_TYPE;
-+ cuib.estsize=0;
-+ delete lc->m_enc_header_needsend;
-+ lc->m_enc_header_needsend=cuib.build();
-+ }
-+ }
-+
-+ if (lc->m_enc)
-+ {
-+ if (lc->m_wavewritefile)
-+ {
-+ lc->m_wavewritefile->WriteFloats((float*)p->Get(),p->GetSize()/sizeof(float));
-+ }
-+ lc->m_enc->Encode((float*)p->Get(),p->GetSize()/sizeof(float));
-+
-+ int s;
-+ while ((s=lc->m_enc->outqueue.Available())>(lc->m_enc_header_needsend?MIN_ENC_BLOCKSIZE*4:MIN_ENC_BLOCKSIZE))
-+ {
-+ if (s > MAX_ENC_BLOCKSIZE) s=MAX_ENC_BLOCKSIZE;
-+
-+ {
-+ mpb_client_upload_interval_write wh;
-+ memcpy(wh.guid,lc->m_curwritefile.guid,sizeof(lc->m_curwritefile.guid));
-+ wh.flags=0;
-+ wh.audio_data=lc->m_enc->outqueue.Get();
-+ wh.audio_data_len=s;
-+ lc->m_curwritefile.Write(wh.audio_data,wh.audio_data_len);
-+
-+ if (lc->m_enc_header_needsend)
-+ {
-+ if (config_debug_level>1)
-+ {
-+ mpb_client_upload_interval_begin dib;
-+ dib.parse(lc->m_enc_header_needsend);
-+ printf("SEND BLOCK HEADER %s\n",guidtostr_tmp(dib.guid));
-+ }
-+ m_netcon->Send(lc->m_enc_header_needsend);
-+ lc->m_enc_header_needsend=0;
-+ }
-+
-+ if (config_debug_level>1) printf("SEND BLOCK %s%s %d bytes\n",guidtostr_tmp(wh.guid),wh.flags&1?"end":"",wh.audio_data_len);
-+
-+ m_netcon->Send(wh.build());
-+ }
-+
-+ lc->m_enc->outqueue.Advance(s);
-+ }
-+ lc->m_enc->outqueue.Compact();
-+ }
-+ lc->m_bq.DisposeBlock(p);
-+ p=0;
-+ }
-+ else
-+ {
-+ if (lc->m_enc)
-+ {
-+ // finish any encoding
-+ lc->m_enc->Encode(NULL,0);
-+
-+ // send any final message, with the last one with a flag
-+ // saying "we're done"
-+ do
-+ {
-+ mpb_client_upload_interval_write wh;
-+ int l=lc->m_enc->outqueue.Available();
-+ if (l>MAX_ENC_BLOCKSIZE) l=MAX_ENC_BLOCKSIZE;
-+
-+ memcpy(wh.guid,lc->m_curwritefile.guid,sizeof(wh.guid));
-+ wh.audio_data=lc->m_enc->outqueue.Get();
-+ wh.audio_data_len=l;
-+
-+ lc->m_curwritefile.Write(wh.audio_data,wh.audio_data_len);
-+
-+ lc->m_enc->outqueue.Advance(l);
-+ wh.flags=lc->m_enc->outqueue.GetSize()>0 ? 0 : 1;
-+
-+ if (lc->m_enc_header_needsend)
-+ {
-+ if (config_debug_level>1)
-+ {
-+ mpb_client_upload_interval_begin dib;
-+ dib.parse(lc->m_enc_header_needsend);
-+ printf("SEND BLOCK HEADER %s\n",guidtostr_tmp(dib.guid));
-+ }
-+ m_netcon->Send(lc->m_enc_header_needsend);
-+ lc->m_enc_header_needsend=0;
-+ }
-+
-+ if (config_debug_level>1) printf("SEND BLOCK %s%s %d bytes\n",guidtostr_tmp(wh.guid),wh.flags&1?"end":"",wh.audio_data_len);
-+ m_netcon->Send(wh.build());
-+ }
-+ while (lc->m_enc->outqueue.Available()>0);
-+ lc->m_enc->outqueue.Compact(); // free any memory left
-+
-+ //delete m_enc;
-+ // m_enc=0;
-+ lc->m_enc->reinit();
-+ }
-+
-+ if (lc->m_enc && lc->bitrate != lc->m_enc_bitrate_used)
-+ {
-+ delete lc->m_enc;
-+ lc->m_enc=0;
-+ }
-+ lc->m_need_header=true;
-+
-+ // end the last encode
-+ }
-+ }
-+ }
-+#endif
-+
-+ return wantsleep;
-+
-+}
-+
-+
-+DecodeState *NJClient::start_decode(unsigned char *guid, unsigned int fourcc)
-+{
-+ DecodeState *newstate=new DecodeState;
-+ memcpy(newstate->guid,guid,sizeof(newstate->guid));
-+
-+ WDL_String s;
-+
-+ makeFilenameFromGuid(&s,guid);
-+
-+ // todo: make plug-in system to allow encoders to add types allowed
-+ // todo: with a preference for 'fourcc' if specified
-+ unsigned int types[]={MAKE_NJ_FOURCC('O','G','G','v')}; // only types we understand
-+
-+ int oldl=strlen(s.Get())+1;
-+ s.Append(".XXXXXXXXX");
-+ unsigned int x;
-+ for (x = 0; !newstate->decode_fp && x < sizeof(types)/sizeof(types[0]); x ++)
-+ {
-+ type_to_string(types[x],s.Get()+oldl);
-+ newstate->decode_fp=fopen(s.Get(),"rb");
-+ }
-+
-+ if (newstate->decode_fp)
-+ {
-+ if (config_savelocalaudio<0)
-+ {
-+ newstate->delete_on_delete.Set(s.Get());
-+ }
-+ newstate->decode_codec= new I_NJDecoder;
-+ // run some decoding
-+
-+ while (newstate->decode_codec->m_samples_used <= 0)
-+ {
-+ int l=fread(newstate->decode_codec->DecodeGetSrcBuffer(128),1,128,newstate->decode_fp);
-+ if (l) newstate->decode_codec->DecodeWrote(l);
-+ if (!l)
-+ {
-+ clearerr(newstate->decode_fp);
-+ break;
-+ }
-+ }
-+ }
-+
-+ return newstate;
-+}
-+
-+float NJClient::GetOutputPeak()
-+{
-+ return (float)output_peaklevel;
-+}
-+
-+void NJClient::ChatMessage_Send(char *parm1, char *parm2, char *parm3, char *parm4, char *parm5)
-+{
-+ if (m_netcon)
-+ {
-+ mpb_chat_message m;
-+ m.parms[0]=parm1;
-+ m.parms[1]=parm2;
-+ m.parms[2]=parm3;
-+ m.parms[3]=parm4;
-+ m.parms[4]=parm5;
-+ m_netcon->Send(m.build());
-+ }
-+}
-+
-+void NJClient::process_samples(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate, int offset, int justmonitor)
-+{
-+ // -36dB/sec
-+ double decay=pow(.25*0.25*0.25,len/(double)srate);
-+ // encode my audio and send to server, if enabled
-+ int u;
-+ m_locchan_cs.Enter();
-+ for (u = 0; u < m_locchannels.GetSize() && u < m_max_localch; u ++)
-+ {
-+ Local_Channel *lc=m_locchannels.Get(u);
-+ int sc=lc->src_channel;
-+ float *src=NULL;
-+ if (sc >= 0 && sc < innch) src=inbuf[sc]+offset;
-+
-+ if (lc->cbf || !src || ChannelMixer)
-+ {
-+ int bytelen=len*(int)sizeof(float);
-+ if (tmpblock.GetSize() < bytelen) tmpblock.Resize(bytelen);
-+
-+ if (ChannelMixer && ChannelMixer(ChannelMixer_User32,inbuf,offset,innch,sc,(float*)tmpblock.Get(),len))
-+ {
-+ // channelmixer succeeded
-+ }
-+ else if (src) memcpy(tmpblock.Get(),src,bytelen);
-+ else memset(tmpblock.Get(),0,bytelen);
-+
-+ src=(float* )tmpblock.Get();
-+
-+ // processor
-+ if (lc->cbf)
-+ {
-+ lc->cbf(src,len,lc->cbf_inst);
-+ }
-+ }
-+
-+ if (!justmonitor && lc->bcast_active)
-+ {
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ lc->m_bq.AddBlock(src,len);
-+#endif
-+ }
-+
-+
-+ // monitor this channel
-+ if ((!m_issoloactive && !lc->muted) || lc->solo)
-+ {
-+ float *out1=outbuf[0]+offset;
-+
-+ float vol1=lc->volume;
-+ if (outnch > 1)
-+ {
-+ float vol2=vol1;
-+ float *out2=outbuf[1]+offset;
-+ if (lc->pan > 0.0f) vol1 *= 1.0f-lc->pan;
-+ else if (lc->pan < 0.0f) vol2 *= 1.0f+lc->pan;
-+
-+ float maxf=(float) (lc->decode_peak_vol*decay);
-+
-+ int x=len;
-+ while (x--)
-+ {
-+ float f=src[0] * vol1;
-+
-+ if (f > maxf) maxf=f;
-+ else if (f < -maxf) maxf=-f;
-+
-+ if (f > 1.0) f=1.0;
-+ else if (f < -1.0) f=-1.0;
-+
-+ *out1++ += f;
-+
-+ f=src[0]*vol2;
-+
-+ if (f > maxf) maxf=f;
-+ else if (f < -maxf) maxf=-f;
-+
-+ if (f > 1.0) f=1.0;
-+ else if (f < -1.0) f=-1.0;
-+
-+ *out2++ += f;
-+ src++;
-+ }
-+ lc->decode_peak_vol=maxf;
-+ }
-+ else
-+ {
-+ float maxf=(float) (lc->decode_peak_vol*decay);
-+ int x=len;
-+ while (x--)
-+ {
-+ float f=*src++ * vol1;
-+ if (f > maxf) maxf=f;
-+ else if (f < -maxf) maxf=-f;
-+
-+ if (f > 1.0) f=1.0;
-+ else if (f < -1.0) f=-1.0;
-+
-+ *out1++ += f;
-+ }
-+ lc->decode_peak_vol=maxf;
-+ }
-+ }
-+ else lc->decode_peak_vol=0.0;
-+ }
-+
-+ m_locchan_cs.Leave();
-+
-+
-+ if (!justmonitor)
-+ {
-+ // mix in all active (subscribed) channels
-+ m_users_cs.Enter();
-+ for (u = 0; u < m_remoteusers.GetSize(); u ++)
-+ {
-+ RemoteUser *user=m_remoteusers.Get(u);
-+ int ch;
-+ if (!user) continue;
-+
-+ for (ch = 0; ch < MAX_USER_CHANNELS; ch ++)
-+ {
-+ float lpan=user->pan+user->channels[ch].pan;
-+ if (lpan<-1.0)lpan=-1.0;
-+ else if (lpan>1.0)lpan=1.0;
-+
-+ bool muteflag;
-+ if (m_issoloactive) muteflag = !(user->solomask & (1<<ch));
-+ else muteflag=(user->mutedmask & (1<<ch)) || user->muted;
-+
-+ if (user->channels[ch].ds)
-+ mixInChannel(muteflag,
-+ user->volume*user->channels[ch].volume,lpan,
-+ user->channels[ch].ds,outbuf,len,srate,outnch,offset,decay);
-+ }
-+ }
-+ m_users_cs.Leave();
-+
-+
-+ // write out wave if necessary
-+
-+ if (waveWrite
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ ||(m_oggWrite&&m_oggComp)
-+#endif
-+ )
-+ {
-+ m_wavebq->AddBlock(outbuf[0]+offset,len,outbuf[outnch>1]+offset);
-+ }
-+ }
-+
-+ // apply master volume, then
-+ {
-+ int x=len;
-+ float *ptr1=outbuf[0]+offset;
-+ float maxf=(float)(output_peaklevel*decay);
-+
-+ if (outnch >= 2)
-+ {
-+ float *ptr2=outbuf[1]+offset;
-+ float vol1=config_mastermute?0.0f:config_mastervolume;
-+ float vol2=vol1;
-+ if (config_masterpan > 0.0f) vol1 *= 1.0f-config_masterpan;
-+ else if (config_masterpan< 0.0f) vol2 *= 1.0f+config_masterpan;
-+
-+ while (x--)
-+ {
-+ float f = *ptr1++ *= vol1;
-+ if (f > maxf) maxf=f;
-+ else if (f < -maxf) maxf=-f;
-+
-+ f = *ptr2++ *= vol2;
-+ if (f > maxf) maxf=f;
-+ else if (f < -maxf) maxf=-f;
-+ }
-+ }
-+ else
-+ {
-+ float vol1=config_mastermute?0.0f:config_mastervolume;
-+ while (x--)
-+ {
-+ float f = *ptr1++ *= vol1;
-+ if (f > maxf) maxf=f;
-+ else if (f < -maxf) maxf=-f;
-+ }
-+ }
-+ output_peaklevel=maxf;
-+ }
-+
-+ // mix in (super shitty) metronome (fucko!!!!)
-+ if (!justmonitor)
-+ {
-+ int metrolen=srate / 100;
-+ double sc=6000.0/(double)srate;
-+ int x;
-+ int um=config_metronome>0.0001f;
-+ double vol1=config_metronome_mute?0.0:config_metronome,vol2=vol1;
-+ float *ptr1=outbuf[0]+offset;
-+ float *ptr2=NULL;
-+ if (outnch > 1)
-+ {
-+ ptr2=outbuf[1]+offset;
-+ if (config_metronome_pan > 0.0f) vol1 *= 1.0f-config_metronome_pan;
-+ else if (config_metronome_pan< 0.0f) vol2 *= 1.0f+config_metronome_pan;
-+ }
-+ for (x = 0; x < len; x ++)
-+ {
-+ if (m_metronome_pos <= 0.0)
-+ {
-+ m_metronome_state=1;
-+ m_metronome_tmp=(m_interval_pos+x)<m_metronome_interval;
-+ m_metronome_pos += (double)m_metronome_interval;
-+ }
-+ m_metronome_pos-=1.0;
-+
-+ if (m_metronome_state>0)
-+ {
-+ if (um)
-+ {
-+ double val=0.0;
-+ if (!m_metronome_tmp) val = sin((double)m_metronome_state*sc*2.0) * 0.25;
-+ else val = sin((double)m_metronome_state*sc);
-+
-+ ptr1[x]+=(float)(val*vol1);
-+ if (ptr2) ptr2[x]+=(float)(val*vol2);
-+ }
-+ if (++m_metronome_state >= metrolen) m_metronome_state=0;
-+
-+ }
-+ }
-+ }
-+
-+}
-+
-+void NJClient::mixInChannel(bool muted, float vol, float pan, DecodeState *chan, float **outbuf, int len, int srate, int outnch, int offs, double vudecay)
-+{
-+ if (!chan->decode_codec || !chan->decode_fp) return;
-+
-+ int needed;
-+ while (chan->decode_codec->m_samples_used <=
-+ (needed=resampleLengthNeeded(chan->decode_codec->GetSampleRate(),srate,len,&chan->resample_state)*chan->decode_codec->GetNumChannels()))
-+ {
-+ int l=fread(chan->decode_codec->DecodeGetSrcBuffer(128),1,128,chan->decode_fp);
-+ chan->decode_codec->DecodeWrote(l);
-+ if (!l)
-+ {
-+ clearerr(chan->decode_fp);
-+ break;
-+ }
-+ }
-+
-+ if (chan->decode_codec->m_samples_used >= needed+chan->dump_samples)
-+ {
-+ float *sptr=(float *)chan->decode_codec->m_samples.Get();
-+
-+ // process VU meter, yay for powerful CPUs
-+ if (!muted && vol > 0.0000001)
-+ {
-+ float *p=sptr;
-+ int l=(needed+chan->dump_samples)*chan->decode_codec->GetNumChannels();
-+ float maxf=(float) (chan->decode_peak_vol*vudecay/vol);
-+ while (l--)
-+ {
-+ float f=*p++;
-+ if (f > maxf) maxf=f;
-+ else if (f < -maxf) maxf=-f;
-+ }
-+ chan->decode_peak_vol=maxf*vol;
-+
-+ float *tmpbuf[2]={outbuf[0]+offs,outnch > 1 ? (outbuf[1]+offs) : 0};
-+ mixFloatsNIOutput(sptr+chan->dump_samples,
-+ chan->decode_codec->GetSampleRate(),
-+ chan->decode_codec->GetNumChannels(),
-+ tmpbuf,
-+ srate,outnch>1?2:1,len,
-+ vol,pan,&chan->resample_state);
-+ }
-+ else
-+ chan->decode_peak_vol=0.0;
-+
-+ // advance the queue
-+ chan->decode_samplesout += needed/chan->decode_codec->GetNumChannels();
-+ chan->decode_codec->m_samples_used -= needed+chan->dump_samples;
-+ memcpy(sptr,sptr+needed+chan->dump_samples,chan->decode_codec->m_samples_used*sizeof(float));
-+ chan->dump_samples=0;
-+ }
-+ else
-+ {
-+
-+ if (config_debug_level>0)
-+ {
-+ static int cnt=0;
-+
-+ char s[512];
-+ guidtostr(chan->guid,s);
-+
-+ char buf[512];
-+ sprintf(buf,"underrun %d at %d on %s, %d/%d samples\n",cnt++,ftell(chan->decode_fp),s,chan->decode_codec->m_samples_used,needed);
-+#ifdef _WIN32
-+ OutputDebugString(buf);
-+#endif
-+ }
-+
-+ chan->decode_samplesout += chan->decode_codec->m_samples_used/chan->decode_codec->GetNumChannels();
-+ chan->decode_codec->m_samples_used=0;
-+ chan->dump_samples+=needed;
-+
-+ }
-+}
-+
-+void NJClient::on_new_interval()
-+{
-+ m_loopcnt++;
-+ writeLog("interval %d %.2f %d\n",m_loopcnt,GetActualBPM(),m_active_bpi);
-+
-+ m_metronome_pos=0.0;
-+
-+ int u;
-+ m_locchan_cs.Enter();
-+ for (u = 0; u < m_locchannels.GetSize() && u < m_max_localch; u ++)
-+ {
-+ Local_Channel *lc=m_locchannels.Get(u);
-+
-+
-+ if (lc->bcast_active)
-+ {
-+ lc->m_bq.AddBlock(NULL,0);
-+ }
-+
-+ int wasact=lc->bcast_active;
-+
-+ lc->bcast_active = lc->broadcasting;
-+
-+ if (wasact && !lc->bcast_active)
-+ {
-+ lc->m_bq.AddBlock(NULL,-1);
-+ }
-+
-+ }
-+ m_locchan_cs.Leave();
-+
-+ m_users_cs.Enter();
-+ for (u = 0; u < m_remoteusers.GetSize(); u ++)
-+ {
-+ RemoteUser *user=m_remoteusers.Get(u);
-+ int ch;
-+// printf("submask=%d,cpm=%d\n",user->submask , user->chanpresentmask);
-+ for (ch = 0; ch < MAX_USER_CHANNELS; ch ++)
-+ {
-+ RemoteUser_Channel *chan=&user->channels[ch];
-+ delete chan->ds;
-+ chan->ds=0;
-+ if ((user->submask & user->chanpresentmask) & (1<<ch)) chan->ds = chan->next_ds[0];
-+ else delete chan->next_ds[0];
-+ chan->next_ds[0]=chan->next_ds[1]; // advance queue
-+ chan->next_ds[1]=0;
-+ ;
-+ if (chan->ds)
-+ {
-+ char guidstr[64];
-+ guidtostr(chan->ds->guid,guidstr);
-+ writeLog("user %s \"%s\" %d \"%s\"\n",guidstr,user->name.Get(),ch,chan->name.Get());
-+ }
-+ }
-+ }
-+ m_users_cs.Leave();
-+
-+ //if (m_enc->isError()) printf("ERROR\n");
-+ //else printf("YAY\n");
-+
-+}
-+
-+
-+char *NJClient::GetUserState(int idx, float *vol, float *pan, bool *mute)
-+{
-+ if (idx<0 || idx>=m_remoteusers.GetSize()) return NULL;
-+ RemoteUser *p=m_remoteusers.Get(idx);
-+ if (vol) *vol=p->volume;
-+ if (pan) *pan=p->pan;
-+ if (mute) *mute=p->muted;
-+ return p->name.Get();
-+}
-+
-+void NJClient::SetUserState(int idx, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute)
-+{
-+ if (idx<0 || idx>=m_remoteusers.GetSize()) return;
-+ RemoteUser *p=m_remoteusers.Get(idx);
-+ if (setvol) p->volume=vol;
-+ if (setpan) p->pan=pan;
-+ if (setmute) p->muted=mute;
-+}
-+
-+int NJClient::EnumUserChannels(int useridx, int i)
-+{
-+ if (useridx<0 || useridx>=m_remoteusers.GetSize()||i<0||i>=MAX_USER_CHANNELS) return -1;
-+ RemoteUser *user=m_remoteusers.Get(useridx);
-+
-+ int x;
-+ for (x = 0; x < 32; x ++)
-+ {
-+ if ((user->chanpresentmask & (1<<x)) && !i--) return x;
-+ }
-+ return -1;
-+}
-+
-+char *NJClient::GetUserChannelState(int useridx, int channelidx, bool *sub, float *vol, float *pan, bool *mute, bool *solo)
-+{
-+ if (useridx<0 || useridx>=m_remoteusers.GetSize()||channelidx<0||channelidx>=MAX_USER_CHANNELS) return NULL;
-+ RemoteUser_Channel *p=m_remoteusers.Get(useridx)->channels + channelidx;
-+ RemoteUser *user=m_remoteusers.Get(useridx);
-+ if (!(user->chanpresentmask & (1<<channelidx))) return 0;
-+
-+ if (sub) *sub=!!(user->submask & (1<<channelidx));
-+ if (vol) *vol=p->volume;
-+ if (pan) *pan=p->pan;
-+ if (mute) *mute=!!(user->mutedmask & (1<<channelidx));
-+ if (solo) *solo=!!(user->solomask & (1<<channelidx));
-+
-+ return p->name.Get();
-+}
-+
-+
-+void NJClient::SetUserChannelState(int useridx, int channelidx,
-+ bool setsub, bool sub, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo)
-+{
-+ if (useridx<0 || useridx>=m_remoteusers.GetSize()||channelidx<0||channelidx>=MAX_USER_CHANNELS) return;
-+ RemoteUser *user=m_remoteusers.Get(useridx);
-+ RemoteUser_Channel *p=user->channels + channelidx;
-+ if (!(user->chanpresentmask & (1<<channelidx))) return;
-+
-+ if (setsub && !!(user->submask&(1<<channelidx)) != sub)
-+ {
-+ // toggle subscription
-+ if (!sub)
-+ {
-+ mpb_client_set_usermask su;
-+ su.build_add_rec(user->name.Get(),(user->submask&=~(1<<channelidx)));
-+ m_netcon->Send(su.build());
-+
-+ DecodeState *tmp,*tmp2,*tmp3;
-+ m_users_cs.Enter();
-+ tmp=p->ds; p->ds=0;
-+ tmp2=p->next_ds[0]; p->next_ds[0]=0;
-+ tmp3=p->next_ds[1]; p->next_ds[1]=0;
-+ m_users_cs.Leave();
-+
-+ delete tmp;
-+ delete tmp2;
-+ delete tmp3;
-+ }
-+ else
-+ {
-+ mpb_client_set_usermask su;
-+ su.build_add_rec(user->name.Get(),(user->submask|=(1<<channelidx)));
-+ m_netcon->Send(su.build());
-+ }
-+
-+ }
-+ if (setvol) p->volume=vol;
-+ if (setpan) p->pan=pan;
-+ if (setmute)
-+ {
-+ if (mute)
-+ user->mutedmask |= (1<<channelidx);
-+ else
-+ user->mutedmask &= ~(1<<channelidx);
-+ }
-+ if (setsolo)
-+ {
-+ if (solo) user->solomask |= (1<<channelidx);
-+ else user->solomask &= ~(1<<channelidx);
-+
-+ if (user->solomask) m_issoloactive|=1;
-+ else
-+ {
-+ int x;
-+ for (x = 0; x < m_remoteusers.GetSize(); x ++)
-+ {
-+ if (m_remoteusers.Get(x)->solomask)
-+ break;
-+ }
-+ if (x == m_remoteusers.GetSize()) m_issoloactive&=~1;
-+ }
-+ }
-+}
-+
-+
-+float NJClient::GetUserChannelPeak(int useridx, int channelidx)
-+{
-+ if (useridx<0 || useridx>=m_remoteusers.GetSize()||channelidx<0||channelidx>=MAX_USER_CHANNELS) return 0.0f;
-+ RemoteUser_Channel *p=m_remoteusers.Get(useridx)->channels + channelidx;
-+ RemoteUser *user=m_remoteusers.Get(useridx);
-+ if (!(user->chanpresentmask & (1<<channelidx))) return 0.0f;
-+ if (!p->ds) return 0.0f;
-+
-+ return (float)p->ds->decode_peak_vol;
-+}
-+
-+float NJClient::GetLocalChannelPeak(int ch)
-+{
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x == m_locchannels.GetSize()) return 0.0f;
-+ Local_Channel *c=m_locchannels.Get(x);
-+ return (float)c->decode_peak_vol;
-+}
-+
-+void NJClient::DeleteLocalChannel(int ch)
-+{
-+ m_locchan_cs.Enter();
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x < m_locchannels.GetSize())
-+ {
-+ delete m_locchannels.Get(x);
-+ m_locchannels.Delete(x);
-+ }
-+ m_locchan_cs.Leave();
-+}
-+
-+void NJClient::SetLocalChannelProcessor(int ch, void (*cbf)(float *, int ns, void *), void *inst)
-+{
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x < m_locchannels.GetSize())
-+ {
-+ m_locchan_cs.Enter();
-+ Local_Channel *c=m_locchannels.Get(x);
-+ c->cbf=cbf;
-+ c->cbf_inst=inst;
-+ m_locchan_cs.Leave();
-+ }
-+}
-+
-+void NJClient::GetLocalChannelProcessor(int ch, void **func, void **inst)
-+{
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x == m_locchannels.GetSize())
-+ {
-+ if (func) *func=0;
-+ if (inst) *inst=0;
-+ return;
-+ }
-+
-+ Local_Channel *c=m_locchannels.Get(x);
-+ if (func) *func=(void *)c->cbf;
-+ if (inst) *inst=c->cbf_inst;
-+}
-+
-+void NJClient::SetLocalChannelInfo(int ch, char *name, bool setsrcch, int srcch,
-+ bool setbitrate, int bitrate, bool setbcast, bool broadcast)
-+{
-+ m_locchan_cs.Enter();
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x == m_locchannels.GetSize())
-+ {
-+ m_locchannels.Add(new Local_Channel);
-+ }
-+
-+ Local_Channel *c=m_locchannels.Get(x);
-+ c->channel_idx=ch;
-+ if (name) c->name.Set(name);
-+ if (setsrcch) c->src_channel=srcch;
-+ if (setbitrate) c->bitrate=bitrate;
-+ if (setbcast) c->broadcasting=broadcast;
-+ m_locchan_cs.Leave();
-+}
-+
-+char *NJClient::GetLocalChannelInfo(int ch, int *srcch, int *bitrate, bool *broadcast)
-+{
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x == m_locchannels.GetSize()) return 0;
-+ Local_Channel *c=m_locchannels.Get(x);
-+ if (srcch) *srcch=c->src_channel;
-+ if (bitrate) *bitrate=c->bitrate;
-+ if (broadcast) *broadcast=c->broadcasting;
-+
-+ return c->name.Get();
-+}
-+
-+int NJClient::EnumLocalChannels(int i)
-+{
-+ if (i<0||i>=m_locchannels.GetSize()) return -1;
-+ return m_locchannels.Get(i)->channel_idx;
-+}
-+
-+
-+void NJClient::SetLocalChannelMonitoring(int ch, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo)
-+{
-+ m_locchan_cs.Enter();
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x == m_locchannels.GetSize())
-+ {
-+ m_locchannels.Add(new Local_Channel);
-+ }
-+
-+ Local_Channel *c=m_locchannels.Get(x);
-+ c->channel_idx=ch;
-+ if (setvol) c->volume=vol;
-+ if (setpan) c->pan=pan;
-+ if (setmute) c->muted=mute;
-+ if (setsolo)
-+ {
-+ c->solo = solo;
-+ if (solo) m_issoloactive|=2;
-+ else
-+ {
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize(); x ++)
-+ {
-+ if (m_locchannels.Get(x)->solo) break;
-+ }
-+ if (x == m_locchannels.GetSize())
-+ m_issoloactive&=~2;
-+ }
-+ }
-+ m_locchan_cs.Leave();
-+}
-+
-+int NJClient::GetLocalChannelMonitoring(int ch, float *vol, float *pan, bool *mute, bool *solo)
-+{
-+ int x;
-+ for (x = 0; x < m_locchannels.GetSize() && m_locchannels.Get(x)->channel_idx!=ch; x ++);
-+ if (x == m_locchannels.GetSize()) return -1;
-+ Local_Channel *c=m_locchannels.Get(x);
-+ if (vol) *vol=c->volume;
-+ if (pan) *pan=c->pan;
-+ if (mute) *mute=c->muted;
-+ if (solo) *solo=c->solo;
-+ return 0;
-+}
-+
-+
-+
-+void NJClient::NotifyServerOfChannelChange()
-+{
-+ if (m_netcon)
-+ {
-+ int x;
-+ mpb_client_set_channel_info sci;
-+ for (x = 0; x < m_locchannels.GetSize(); x ++)
-+ {
-+ Local_Channel *ch=m_locchannels.Get(x);
-+ sci.build_add_rec(ch->name.Get(),0,0,0);
-+ }
-+ m_netcon->Send(sci.build());
-+ }
-+}
-+
-+void NJClient::SetWorkDir(char *path)
-+{
-+ m_workdir.Set(path?path:"");
-+
-+ if (!path || !*path) return;
-+
-+
-+ if (path[0] && path[strlen(path)-1] != '/' && path[strlen(path)-1] != '\\')
-+#ifdef _WIN32
-+ m_workdir.Append("\\");
-+#else
-+ m_workdir.Append("/");
-+#endif
-+
-+ // create subdirectories for ogg files
-+ int a;
-+ for (a = 0; a < 16; a ++)
-+ {
-+ WDL_String tmp(m_workdir.Get());
-+ char buf[5];
-+ sprintf(buf,"%x",a);
-+ tmp.Append(buf);
-+#ifdef _WIN32
-+ CreateDirectory(tmp.Get(),NULL);
-+#else
-+ mkdir(tmp.Get(),0700);
-+#endif
-+ }
-+}
-+
-+
-+RemoteUser_Channel::RemoteUser_Channel() : volume(1.0f), pan(0.0f), ds(NULL)
-+{
-+ memset(next_ds,0,sizeof(next_ds));
-+}
-+
-+RemoteUser_Channel::~RemoteUser_Channel()
-+{
-+ delete ds;
-+ ds=NULL;
-+ delete next_ds[0];
-+ delete next_ds[1];
-+ memset(next_ds,0,sizeof(next_ds));
-+}
-+
-+
-+RemoteDownload::RemoteDownload() : chidx(-1), playtime(0), fp(0)
-+{
-+ memset(&guid,0,sizeof(guid));
-+ time(&last_time);
-+}
-+
-+RemoteDownload::~RemoteDownload()
-+{
-+ Close();
-+}
-+
-+void RemoteDownload::Close()
-+{
-+ if (fp) fclose(fp);
-+ fp=0;
-+ startPlaying(1);
-+}
-+
-+void RemoteDownload::Open(NJClient *parent, unsigned int fourcc)
-+{
-+ m_parent=parent;
-+ Close();
-+ WDL_String s;
-+ parent->makeFilenameFromGuid(&s,guid);
-+
-+
-+ // append extension from fourcc
-+ char buf[8];
-+ type_to_string(fourcc, buf);
-+ s.Append(".");
-+ s.Append(buf);
-+
-+ m_fourcc=fourcc;
-+ fp=fopen(s.Get(),"wb");
-+}
-+
-+void RemoteDownload::startPlaying(int force)
-+{
-+ if (m_parent && chidx >= 0 && (force || (playtime && fp && ftell(fp)>playtime)))
-+ // wait until we have config_play_prebuffer of data to start playing, or if config_play_prebuffer is 0, we are forced to play (download finished)
-+ {
-+ int x;
-+ RemoteUser *theuser;
-+ for (x = 0; x < m_parent->m_remoteusers.GetSize() && strcmp((theuser=m_parent->m_remoteusers.Get(x))->name.Get(),username.Get()); x ++);
-+ if (x < m_parent->m_remoteusers.GetSize() && chidx >= 0 && chidx < MAX_USER_CHANNELS)
-+ {
-+ DecodeState *tmp=m_parent->start_decode(guid,m_fourcc);
-+
-+ DecodeState *tmp2;
-+ m_parent->m_users_cs.Enter();
-+ int useidx=!!theuser->channels[chidx].next_ds[0];
-+ tmp2=theuser->channels[chidx].next_ds[useidx];
-+ theuser->channels[chidx].next_ds[useidx]=tmp;
-+ m_parent->m_users_cs.Leave();
-+ delete tmp2;
-+ }
-+ chidx=-1;
-+ }
-+}
-+
-+void RemoteDownload::Write(void *buf, int len)
-+{
-+ int pos=len;
-+ if (fp)
-+ {
-+ fwrite(buf,1,len,fp);
-+ fflush(fp);
-+ pos = ftell(fp);
-+ }
-+
-+ startPlaying();
-+}
-+
-+
-+Local_Channel::Local_Channel() : channel_idx(0), src_channel(0), volume(1.0f), pan(0.0f),
-+ muted(false), solo(false), broadcasting(false),
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ m_enc(NULL),
-+ m_enc_bitrate_used(0),
-+ m_enc_header_needsend(NULL),
-+#endif
-+ bcast_active(false), cbf(NULL), cbf_inst(NULL),
-+ bitrate(64), m_need_header(true), m_wavewritefile(NULL),
-+ decode_peak_vol(0.0)
-+{
-+}
-+
-+
-+int BufferQueue::GetBlock(WDL_HeapBuf **b) // return 0 if got one, 1 if none avail
-+{
-+ m_cs.Enter();
-+ if (m_samplequeue.Available())
-+ {
-+ *b=*(WDL_HeapBuf **)m_samplequeue.Get();
-+ m_samplequeue.Advance(sizeof(WDL_HeapBuf *));
-+ if (m_samplequeue.Available()<256) m_samplequeue.Compact();
-+ m_cs.Leave();
-+ return 0;
-+ }
-+ m_cs.Leave();
-+ return 1;
-+}
-+
-+void BufferQueue::DisposeBlock(WDL_HeapBuf *b)
-+{
-+ m_cs.Enter();
-+ if (b && (int)b != -1) m_emptybufs.Add(b);
-+ m_cs.Leave();
-+}
-+
-+
-+void BufferQueue::AddBlock(float *samples, int len, float *samples2)
-+{
-+ WDL_HeapBuf *mybuf=0;
-+ if (len>0)
-+ {
-+ m_cs.Enter();
-+
-+ if (m_samplequeue.Available() > 512)
-+ {
-+ m_cs.Leave();
-+ return;
-+ }
-+ int tmp;
-+ if ((tmp=m_emptybufs.GetSize()))
-+ {
-+ mybuf=m_emptybufs.Get(tmp-1);
-+ if (mybuf) m_emptybufs.Delete(tmp-1);
-+ }
-+ m_cs.Leave();
-+ if (!mybuf) mybuf=new WDL_HeapBuf;
-+
-+ int uselen=len*sizeof(float);
-+ if (samples2)
-+ {
-+ uselen+=uselen;
-+ }
-+
-+ mybuf->Resize(uselen);
-+
-+ memcpy(mybuf->Get(),samples,len*sizeof(float));
-+ if (samples2)
-+ memcpy((float*)mybuf->Get()+len,samples2,len*sizeof(float));
-+ }
-+ else if (len == -1) mybuf=(WDL_HeapBuf *)-1;
-+
-+ m_cs.Enter();
-+ m_samplequeue.Add(&mybuf,sizeof(mybuf));
-+ m_cs.Leave();
-+}
-+
-+Local_Channel::~Local_Channel()
-+{
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ delete m_enc;
-+ m_enc=0;
-+ delete m_enc_header_needsend;
-+ m_enc_header_needsend=0;
-+#endif
-+
-+ delete m_wavewritefile;
-+ m_wavewritefile=0;
-+
-+}
-+
-+void NJClient::SetOggOutFile(FILE *fp, int srate, int nch, int bitrate)
-+{
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ if (m_oggWrite)
-+ {
-+ if (m_oggComp)
-+ {
-+ m_oggComp->Encode(NULL,0);
-+ if (m_oggComp->outqueue.Available())
-+ fwrite((char *)m_oggComp->outqueue.Get(),1,m_oggComp->outqueue.Available(),m_oggWrite);
-+ }
-+ fclose(m_oggWrite);
-+ m_oggWrite=0;
-+ }
-+ delete m_oggComp;
-+ m_oggComp=0;
-+
-+ if (fp)
-+ {
-+ //fucko
-+ m_oggComp=new I_NJEncoder(srate,nch,bitrate,WDL_RNG_int32());
-+ m_oggWrite=fp;
-+ }
-+#endif
-+}
-+
-diff -Naur ninjam-cclient-0.01a/src/njclient.h ninjam/src/njclient.h
---- ninjam-cclient-0.01a/src/njclient.h 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/njclient.h 2005-08-30 03:16:06.000000000 +0000
-@@ -0,0 +1,263 @@
-+/*
-+ NINJAM - njclient.h
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This file defines the interface for the NJClient class, which handles
-+ the bulk of logic and state of the client.
-+
-+ The basic premise of the NJClient class is, the UI code tells NJClient
-+ when the user tweaks something, and NJClient tells the UI code when
-+ it needs to update something.
-+
-+ NJClient::Run() needs to be called regularly (preferably every 50ms or less).
-+ When calling, if Run() returns 0, you should immediately call it again. i.e.:
-+
-+ while (!myClient->Run());
-+
-+ Is how Run() should usually be called. In general it is easier to call Run()
-+ from the UI thread in a timer, for example, but it turns out it's a lot better
-+ to call it from its own thread to ensure that some UI issue doesn't end up
-+ stalling it. If you go this route, you will want to put the Run() call inside
-+ of a mutex lock, and also any code that reads/writes remote channel state or
-+ writes to local channel state, in that mutex lock as well. This is a bit of
-+ a pain, but not really that bad.
-+
-+ Additionally, NJClient::AudioProc() needs to be called from the audio thread.
-+ It is not necessary to do any sort of mutex protection around these calls,
-+ though, as they are done internally.
-+
-+
-+ Some other notes:
-+
-+ + Currently only OGG Vorbis is supported. There's hooks in there to add support
-+ for more formats, but the requirements for the formats are a little high, so
-+ currently OGG Vorbis is the only thing we've seen that would work well. And it
-+ really rocks for this application.
-+
-+ + OK maybe that's it for now? :)
-+
-+*/
-+
-+#ifndef _NJCLIENT_H_
-+#define _NJCLIENT_H_
-+
-+#ifdef _WIN32
-+#include <windows.h>
-+#else
-+#include <stdlib.h>
-+#include <memory.h>
-+#endif
-+#include <stdio.h>
-+#include <time.h>
-+#include "../WDL/string.h"
-+#include "../WDL/ptrlist.h"
-+#include "../WDL/jnetlib/jnetlib.h"
-+#include "../WDL/sha.h"
-+#include "../WDL/rng.h"
-+#include "../WDL/mutex.h"
-+
-+#include "../WDL/wavwrite.h"
-+
-+#include "netmsg.h"
-+
-+
-+class I_NJEncoder;
-+class RemoteDownload;
-+class RemoteUser;
-+class Local_Channel;
-+class DecodeState;
-+class BufferQueue;
-+
-+// #define NJCLIENT_NO_XMIT_SUPPORT // might want to do this for njcast :)
-+// it also removes mixed ogg writing support
-+
-+class NJClient
-+{
-+ friend class RemoteDownload;
-+public:
-+ NJClient();
-+ ~NJClient();
-+
-+ void Connect(char *host, char *user, char *pass);
-+ void Disconnect();
-+
-+ // call Run() from your main (UI) thread
-+ int Run();// returns nonzero if sleep is OK
-+
-+ char *GetErrorStr() { return m_errstr.Get(); }
-+
-+ int IsAudioRunning() { return m_audio_enable; }
-+ // call AudioProc, (and only AudioProc) from your audio thread
-+ void AudioProc(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate); // len is number of sample pairs or samples
-+
-+
-+ // basic configuration
-+ int config_autosubscribe;
-+ int config_savelocalaudio; // set 1 to save compressed files, set to 2 to save .wav files as well.
-+ // -1 makes it try to delete the remote .oggs as soon as possible
-+
-+ float config_metronome,config_metronome_pan; // volume of metronome
-+ bool config_metronome_mute;
-+ float config_mastervolume,config_masterpan; // master volume
-+ bool config_mastermute;
-+ int config_debug_level;
-+ int config_play_prebuffer; // -1 means play instantly, 0 means play when full file is there, otherwise refers to how many
-+ // bytes of compressed source to have before play. the default value is 4096.
-+
-+ float GetOutputPeak();
-+
-+ enum { NJC_STATUS_DISCONNECTED=-3,NJC_STATUS_INVALIDAUTH=-2, NJC_STATUS_CANTCONNECT=-1, NJC_STATUS_OK=0, NJC_STATUS_PRECONNECT};
-+ int GetStatus();
-+
-+ void SetWorkDir(char *path);
-+ char *GetWorkDir() { return m_workdir.Get(); }
-+
-+ char *GetUserName() { return m_user.Get(); }
-+ char *GetHostName() { return m_host.Get(); }
-+
-+ float GetActualBPM() { return (float) m_active_bpm; }
-+ int GetBPI() { return m_active_bpi; }
-+ void GetPosition(int *pos, int *length); // positions in samples
-+ int GetLoopCount() { return m_loopcnt; }
-+ unsigned int GetSessionPosition(); // returns milliseconds
-+
-+ int HasUserInfoChanged() { if (m_userinfochange) { m_userinfochange=0; return 1; } return 0; }
-+ int GetNumUsers() { return m_remoteusers.GetSize(); }
-+ char *GetUserState(int idx, float *vol=0, float *pan=0, bool *mute=0);
-+ void SetUserState(int idx, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute);
-+
-+ float GetUserChannelPeak(int useridx, int channelidx);
-+ char *GetUserChannelState(int useridx, int channelidx, bool *sub=0, float *vol=0, float *pan=0, bool *mute=0, bool *solo=0);
-+ void SetUserChannelState(int useridx, int channelidx, bool setsub, bool sub, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo);
-+ int EnumUserChannels(int useridx, int i); // returns <0 if out of channels. start with i=0, and go upwards
-+
-+ int GetMaxLocalChannels() { return m_max_localch; }
-+ void DeleteLocalChannel(int ch);
-+ int EnumLocalChannels(int i);
-+ float GetLocalChannelPeak(int ch);
-+ void SetLocalChannelProcessor(int ch, void (*cbf)(float *, int ns, void *), void *inst);
-+ void GetLocalChannelProcessor(int ch, void **func, void **inst);
-+ void SetLocalChannelInfo(int ch, char *name, bool setsrcch, int srcch, bool setbitrate, int bitrate, bool setbcast, bool broadcast);
-+ char *GetLocalChannelInfo(int ch, int *srcch, int *bitrate, bool *broadcast);
-+ void SetLocalChannelMonitoring(int ch, bool setvol, float vol, bool setpan, float pan, bool setmute, bool mute, bool setsolo, bool solo);
-+ int GetLocalChannelMonitoring(int ch, float *vol, float *pan, bool *mute, bool *solo); // 0 on success
-+ void NotifyServerOfChannelChange(); // call after any SetLocalChannel* that occur after initial connect
-+
-+ int IsASoloActive() { return m_issoloactive; }
-+
-+ void SetLogFile(char *name=NULL);
-+
-+ void SetOggOutFile(FILE *fp, int srate, int nch, int bitrate=128);
-+ WaveWriter *waveWrite;
-+
-+
-+ int LicenseAgreement_User32;
-+ int (*LicenseAgreementCallback)(int user32, char *licensetext); // return TRUE if user accepts
-+
-+
-+ // messages you can send:
-+ // "MSG" "text" - broadcast "text" to everybody
-+ // "PRIVMSG" "username" "text" - send text to "username"
-+ void ChatMessage_Send(char *parm1, char *parm2, char *parm3=NULL, char *parm4=NULL, char *parm5=NULL);
-+
-+ // messages you can receive from this:
-+ // "MSG" "user" "text" - message from user to everybody (including you!), or if user is empty, from the server
-+ // "PRIVMSG "user" "text" - private message from user
-+
-+ // usernames are not case sensitive, but message names ARE.
-+
-+ // note that nparms is the MAX number of parms, you still can get NULL parms entries in there (though rarely)
-+ void (*ChatMessage_Callback)(int user32, NJClient *inst, char **parms, int nparms);
-+ int ChatMessage_User32;
-+
-+
-+ // set these if you want to mix multiple channels into the output channel
-+ // return 0 if you want the default behavior
-+ int (*ChannelMixer)(int user32, float **inbuf, int in_offset, int innch, int chidx, float *outbuf, int len);
-+ int ChannelMixer_User32;
-+
-+
-+protected:
-+ double output_peaklevel;
-+
-+ void _reinit();
-+
-+ void makeFilenameFromGuid(WDL_String *s, unsigned char *guid);
-+
-+ void updateBPMinfo(int bpm, int bpi);
-+ void process_samples(float **inbuf, int innch, float **outbuf, int outnch, int len, int srate, int offset, int justmonitor=0);
-+ void on_new_interval();
-+
-+ void writeLog(char *fmt, ...);
-+
-+ WDL_String m_errstr;
-+
-+ WDL_String m_workdir;
-+ int m_status;
-+ int m_max_localch;
-+ int m_connection_keepalive;
-+ FILE *m_logFile;
-+#ifndef NJCLIENT_NO_XMIT_SUPPORT
-+ FILE *m_oggWrite;
-+ I_NJEncoder *m_oggComp;
-+#endif
-+
-+ WDL_String m_user, m_pass, m_host;
-+
-+ int m_in_auth;
-+ int m_bpm,m_bpi;
-+ int m_beatinfo_updated;
-+ int m_audio_enable;
-+ int m_srate;
-+ int m_userinfochange;
-+ int m_issoloactive;
-+
-+ unsigned int m_session_pos_ms,m_session_pos_samples; // samples just keeps track of any samples lost to precision errors
-+
-+ int m_loopcnt;
-+ int m_active_bpm, m_active_bpi;
-+ int m_interval_length;
-+ int m_interval_pos, m_metronome_state, m_metronome_tmp,m_metronome_interval;
-+ double m_metronome_pos;
-+
-+ DecodeState *start_decode(unsigned char *guid, unsigned int fourcc=0);
-+
-+ BufferQueue *m_wavebq;
-+
-+ WDL_PtrList<Local_Channel> m_locchannels;
-+
-+ void mixInChannel(bool muted, float vol, float pan, DecodeState *chan, float **outbuf, int len, int srate, int outnch, int offs, double vudecay);
-+
-+ WDL_Mutex m_users_cs, m_locchan_cs, m_log_cs, m_misc_cs;
-+ Net_Connection *m_netcon;
-+ WDL_PtrList<RemoteUser> m_remoteusers;
-+ WDL_PtrList<RemoteDownload> m_downloads;
-+
-+ WDL_HeapBuf tmpblock;
-+};
-+
-+
-+
-+#define MAX_USER_CHANNELS 32
-+#define MAX_LOCAL_CHANNELS 32 // probably want to use NJClient::GetMaxLocalChannels() if determining when it's OK to add a channel,etc
-+#define DOWNLOAD_TIMEOUT 8
-+
-+
-+#endif//_NJCLIENT_H_
-diff -Naur ninjam-cclient-0.01a/src/njmisc.cpp ninjam/src/njmisc.cpp
---- ninjam-cclient-0.01a/src/njmisc.cpp 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/njmisc.cpp 2006-01-18 19:30:48.023054632 +0000
-@@ -0,0 +1,156 @@
-+/*
-+ NINJAM - njmisc.cpp
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+
-+/*
-+
-+ Some utility functions common to clients.
-+
-+*/
-+
-+
-+#ifdef _WIN32
-+#include <windows.h>
-+#endif
-+
-+#include <string.h>
-+#include <stdio.h>
-+#include <math.h>
-+#include <float.h>
-+
-+#include "njmisc.h"
-+
-+// dB related utilities
-+
-+double DB2SLIDER(double x)
-+{
-+ double d=pow(2110.54*fabs(x),1.0/3.0);
-+ if (x < 0.0) d=-d;
-+ return d + 63.0;
-+}
-+
-+double SLIDER2DB(double y)
-+{
-+ return pow(y-63.0,3.0) * (1.0/2110.54);
-+}
-+
-+double VAL2DB(double x)
-+{
-+ static double g_ilog2x6;
-+ static int a;
-+ if (!a)
-+ {
-+ a++;
-+ g_ilog2x6 = 6.0/log10(2.0);
-+ }
-+ double v=(log10(x)*g_ilog2x6);
-+ if (v < -120.0) v=-120.0;
-+ return v;
-+}
-+
-+void mkvolpanstr(char *str, double vol, double pan)
-+{
-+ mkvolstr(str,vol);
-+ char *p=str+strlen(str);
-+ *p++=' ';
-+ mkpanstr(p,pan);
-+}
-+
-+void mkpanstr(char *str, double pan)
-+{
-+ if (fabs(pan) < 0.0001) strcpy(str,"center");
-+ else sprintf(str,"%d%%%s", (int)fabs(pan*100.0),(pan>0.0 ? "R" : "L"));
-+}
-+
-+void mkvolstr(char *str, double vol)
-+{
-+ double v=VAL2DB(vol);
-+ if (vol < 0.0000001 || v < -120.0) v=-120.0;
-+ sprintf(str,"%s%2.1fdB",v>0.0?"+":"",v);
-+}
-+
-+
-+
-+/// jesusonic interfacing
-+
-+#ifdef _WIN32
-+
-+void deleteJesusonicProc(void *i, int chi)
-+{
-+ if (JesusonicAPI && i)
-+ {
-+ char buf[4096];
-+ sprintf(buf,"%s\\ninjam.p%02d",jesusdir.Get()[0]?jesusdir.Get():".",chi);
-+ JesusonicAPI->preset_save(i,buf);
-+ JesusonicAPI->ui_wnd_destroy(i);
-+ JesusonicAPI->set_opts(i,-1,-1,1);
-+ JesusonicAPI->ui_quit(i);
-+ JesusonicAPI->destroyInstance(i);
-+ }
-+}
-+
-+
-+void jesusonic_processor(float *buf, int len, void *inst)
-+{
-+ if (inst)
-+ {
-+ _controlfp(_RC_CHOP,_MCW_RC);
-+ JesusonicAPI->jesus_process_samples(inst,(char*)buf,len*sizeof(float));
-+ JesusonicAPI->osc_run(inst,(char*)buf,len);
-+ }
-+}
-+
-+
-+void JesusUpdateInfo(void *myInst, char *chdesc, int srate)
-+{
-+ if (myInst)
-+ {
-+ JesusonicAPI->set_sample_fmt(myInst,srate,1,33);
-+ WDL_String tmp("NINJAM embedded: ");
-+ tmp.Append(chdesc);
-+ JesusonicAPI->set_status(myInst,"",tmp.Get());
-+ }
-+}
-+
-+void *CreateJesusInstance(int a, char *chdesc, int srate)
-+{
-+ if (JesusonicAPI)
-+ {
-+ void *myInst=JesusonicAPI->createInstance();
-+ if (!myInst) return 0;
-+ JesusonicAPI->set_rootdir(myInst,jesusdir.Get());
-+ JesusonicAPI->ui_init(myInst);
-+ JesusonicAPI->set_opts(myInst,1,1,-1);
-+
-+ JesusUpdateInfo(myInst,chdesc,srate);
-+
-+ char buf[4096];
-+ sprintf(buf,"%s\\ninjam.p%02d",jesusdir.Get()[0]?jesusdir.Get():".",a);
-+
-+ JesusonicAPI->preset_load(myInst,buf);
-+
-+ return (void *)myInst;
-+ }
-+ return 0;
-+}
-+
-+
-+
-+#endif
-+
-diff -Naur ninjam-cclient-0.01a/src/njmisc.h ninjam/src/njmisc.h
---- ninjam-cclient-0.01a/src/njmisc.h 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/src/njmisc.h 2006-01-18 19:29:50.245838104 +0000
-@@ -0,0 +1,55 @@
-+/*
-+ NINJAM - njmisc.h
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ NINJAM 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.
-+
-+ NINJAM 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 NINJAM; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ Some utility functions common to clients.
-+
-+*/
-+
-+#ifndef _NJMISC_H_
-+#define _NJMISC_H_
-+
-+// some utility functions
-+double DB2SLIDER(double x);
-+double SLIDER2DB(double y);
-+double VAL2DB(double x);
-+#define DB2VAL(x) (pow(2.0,(x)/6.0))
-+void mkvolpanstr(char *str, double vol, double pan);
-+void mkvolstr(char *str, double vol);
-+void mkpanstr(char *str, double pan);
-+
-+#ifdef _WIN32
-+
-+#include "../../WDL/string.h"
-+#include "../../jesusonic/jesusonic_dll.h"
-+
-+extern WDL_String jesusdir;
-+extern jesusonicAPI *JesusonicAPI;
-+
-+void *CreateJesusInstance(int a, char *chdesc, int srate);
-+void JesusUpdateInfo(void *myInst, char *chdesc, int srate);
-+void deleteJesusonicProc(void *i, int chi);
-+void jesusonic_processor(float *buf, int len, void *inst);
-+
-+
-+#endif
-+
-+#endif
-+
-diff -Naur ninjam-cclient-0.01a/WDL/1 ninjam/WDL/1
---- ninjam-cclient-0.01a/WDL/1 1970-01-01 00:00:00.000000000 +0000
-+++ ninjam/WDL/1 2006-01-18 19:22:40.371188984 +0000
-@@ -0,0 +1,250 @@
-+/*
-+ WDL - wavwrite.h
-+ Copyright (C) 2005 Cockos Incorporated
-+
-+ WDL is dual-licensed. You may modify and/or distribute WDL under either of
-+ the following licenses:
-+
-+ This software is provided 'as-is', without any express or implied
-+ warranty. In no event will the authors be held liable for any damages
-+ arising from the use of this software.
-+
-+ Permission is granted to anyone to use this software for any purpose,
-+ including commercial applications, and to alter it and redistribute it
-+ freely, subject to the following restrictions:
-+
-+ 1. The origin of this software must not be misrepresented; you must not
-+ claim that you wrote the original software. If you use this software
-+ in a product, an acknowledgment in the product documentation would be
-+ appreciated but is not required.
-+ 2. Altered source versions must be plainly marked as such, and must not be
-+ misrepresented as being the original software.
-+ 3. This notice may not be removed or altered from any source distribution.
-+
-+
-+ or:
-+
-+ WDL 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.
-+
-+ WDL 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 WDL; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+/*
-+
-+ This file provides a simple class for writing PCM WAV files.
-+
-+*/
-+
-+
-+#ifndef _WAVWRITE_H_
-+#define _WAVWRITE_H_
-+
-+
-+#include <stdio.h>
-+#include "pcmfmtcvt.h"
-+
-+class WaveWriter
-+{
-+ public:
-+ // appending doesnt check sample types
-+ WaveWriter()
-+ {
-+ m_fp=0;
-+ m_bps=0;
-+ m_srate=0;
-+ m_nch=0;
-+ }
-+
-+ WaveWriter(char *filename, int bps, int nch, int srate, int allow_append=1)
-+ {
-+ m_fp=0;
-+ m_bps=0;
-+ m_srate=0;
-+ m_nch=0;
-+ Open(filename,bps,nch,srate,allow_append);
-+
-+ }
-+
-+ int Open(char *filename, int bps, int nch, int srate, int allow_append=1)
-+ {
-+ m_fp=0;
-+ if (allow_append)
-+ {
-+ m_fp=fopen(filename,"r+b");
-+ if (m_fp)
-+ {
-+ fseek(m_fp,0,SEEK_END);
-+ int pos=ftell(m_fp);
-+ if (pos < 44)
-+ {
-+ char buf[44]={0,};
-+ fwrite(buf,1,44-pos,m_fp);
-+ }
-+ }
-+ }
-+ if (!m_fp)
-+ {
-+ m_fp=fopen(filename,"wb");
-+ char tbuf[44];
-+ fwrite(tbuf,1,44,m_fp); // room for header
-+ }
-+ m_bps=bps;
-+ m_nch=nch>1?2:1;
-+ m_srate=srate;
-+
-+ return !!m_fp;
-+ }
-+
-+ ~WaveWriter()
-+ {
-+ if (m_fp)
-+ {
-+ int bytelen=ftell(m_fp)-44;
-+ fseek(m_fp,0,SEEK_SET);
-+
-+ // write header
-+ fwrite("RIFF",1,4,m_fp);
-+ int riff_size=bytelen+44-8;
-+ int x;
-+ for (x = 0; x < 32; x += 8)
-+ {
-+ unsigned char c=(riff_size>>x)&255;
-+ fwrite(&c,1,1,m_fp);
-+ }
-+ fwrite("WAVEfmt \x10\0\0\0",1,12,m_fp);
-+ fwrite("\1\0",1,2,m_fp); // PCM
-+
-+ for (x = 0; x < 16; x += 8) // nch
-+ {
-+ char c=(m_nch>>x)&255;
-+ fwrite(&c,1,1,m_fp);
-+ }
-+ for (x = 0; x < 32; x += 8) // srate
-+ {
-+ char c=(m_srate>>x)&255;
-+ fwrite(&c,1,1,m_fp);
-+ }
-+ for (x = 0; x < 32; x += 8) // bytes_per_sec
-+ {
-+ char c=((m_nch * (m_bps/8) * m_srate)>>x)&255;
-+ fwrite(&c,1,1,m_fp);
-+ }
-+ int blockalign=m_nch * (m_bps/8);
-+ for (x = 0; x < 16; x += 8) // block alignment
-+ {
-+ char c=(blockalign>>x)&255;
-+ fwrite(&c,1,1,m_fp);
-+ }
-+ for (x = 0; x < 16; x += 8) // bits/sample
-+ {
-+ char c=((m_bps&~7)>>x)&255;
-+ fwrite(&c,1,1,m_fp);
-+ }
-+ fwrite("data",1,4,m_fp);
-+ for (x = 0; x < 32; x += 8) // size
-+ {
-+ char c=((bytelen)>>x)&255;
-+ fwrite(&c,1,1,m_fp);
-+ }
-+
-+ fclose(m_fp);
-+ m_fp=0;
-+ }
-+ }
-+
-+ int Status() { return !!m_fp; }
-+
-+ void WriteRaw(void *buf, int len)
-+ {
-+ if (m_fp) fwrite(buf,1,len,m_fp);
-+ }
-+
-+ void WriteFloats(float *samples, int nsamples)
-+ {
-+ if (!m_fp) return;
-+
-+ if (m_bps == 16)
-+ {
-+ while (nsamples-->0)
-+ {
-+ short a;
-+ float_TO_INT16(a,*samples);
-+ unsigned char c=a&0xff;
-+ fwrite(&c,1,1,m_fp);
-+ c=a>>8;
-+ fwrite(&c,1,1,m_fp);
-+ samples++;
-+ }
-+ }
-+ else if (m_bps == 24)
-+ {
-+ while (nsamples-->0)
-+ {
-+ unsigned char a[3];
-+ float_to_i24(samples,a);
-+ fwrite(a,1,3,m_fp);
-+ samples++;
-+ }
-+ }
-+ }
-+
-+ void WriteFloatsNI(float **samples, int offs, int nsamples)
-+ {
-+ if (!m_fp) return;
-+ float *tmpptrs[2]={samples[0]+offs,m_nch>1?samples[1]+offs:NULL};
-+
-+ if (m_bps == 16)
-+ {
-+ while (nsamples-->0)
-+ {
-+ int ch;
-+ for (ch = 0; ch < m_nch; ch ++)
-+ {
-+ short a;
-+ float_TO_INT16(a,tmpptrs[ch][0]);
-+ unsigned char c=a&0xff;
-+ fwrite(&c,1,1,m_fp);
-+ c=a>>8;
-+ fwrite(&c,1,1,m_fp);
-+ tmpptrs[ch]++;
-+ }
-+ }
-+ }
-+ else if (m_bps == 24)
-+ {
-+ while (nsamples-->0)
-+ {
-+ int ch;
-+ for (ch = 0; ch < m_nch; ch ++)
-+ {
-+ unsigned char a[3];
-+ float_to_i24(tmpptrs[ch],a);
-+ fwrite(a,1,3,m_fp);
-+ tmpptrs[ch]++;
-+ }
-+ }
-+ }
-+ }
-+
-+ int get_nch() { return m_nch; }
-+ int get_srate() { return m_srate; }
-+ int get_bps() { return m_bps; }
-+
-+ private:
-+ FILE *m_fp;
-+ int m_bps,m_nch,m_srate;
-+};
-+
-+
-+#endif//_WAVWRITE_H
-+_
-diff -Naur ninjam-cclient-0.01a/WDL/mutex.h ninjam/WDL/mutex.h
---- ninjam-cclient-0.01a/WDL/mutex.h 2005-08-30 03:33:10.000000000 +0000
-+++ ninjam/WDL/mutex.h 2006-01-18 19:20:43.932890296 +0000
-@@ -115,4 +115,5 @@
-
- };
-
--#endif
-\ Kein Zeilenumbruch am Dateiende.
-+#endif
-+
-diff -Naur ninjam-cclient-0.01a/WDL/pcmfmtcvt.h ninjam/WDL/pcmfmtcvt.h
---- ninjam-cclient-0.01a/WDL/pcmfmtcvt.h 2005-08-30 03:33:10.000000000 +0000
-+++ ninjam/WDL/pcmfmtcvt.h 2006-01-09 18:48:39.000000000 +0000
-@@ -402,4 +402,5 @@
- }
-
-
--#endif //_PCMFMTCVT_H_
-\ Kein Zeilenumbruch am Dateiende.
-+#endif //_PCMFMTCVT_H_
-+
-diff -Naur ninjam-cclient-0.01a/WDL/wavwrite.h ninjam/WDL/wavwrite.h
---- ninjam-cclient-0.01a/WDL/wavwrite.h 2005-08-30 03:33:10.000000000 +0000
-+++ ninjam/WDL/wavwrite.h 2006-01-18 19:24:49.017631752 +0000
-@@ -246,4 +246,5 @@
- };
-
-
--#endif//_WAVWRITE_H_
-\ Kein Zeilenumbruch am Dateiende.
-+#endif//_WAVWRITE_H
-+
Added: trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-Makefile.patch
===================================================================
--- trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-Makefile.patch (rev 0)
+++ trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-Makefile.patch 2010-10-26 17:39:25 UTC (rev 1784)
@@ -0,0 +1,25 @@
+--- ninjam/cursesclient/Makefile.old 2010-10-26 18:24:21.000000000 +0100
++++ ninjam/cursesclient/Makefile 2010-10-26 18:28:12.000000000 +0100
+@@ -2,7 +2,7 @@
+ # CPU optimization section
+ #############################################################
+
+-OPTFLAGS = -O2
++OPTFLAGS ?= -O2
+
+ ifdef MAC
+ OPTFLAGS += -D_MAC -mcpu=7450
+@@ -17,10 +17,10 @@
+ #############################################################
+
+ # we MUST have -fomit-frame-pointer and -lm, otherwise we hate life
+-CFLAGS = $(OPTFLAGS) -s
++#CFLAGS = $(OPTFLAGS) -s
+ # CFLAGS += -Wshadow
+-CC=gcc
+-CXX=g++
++CC ?= gcc
++CXX ?= g++
+
+ OBJS = ../../WDL/jnetlib/asyncdns.o
+ OBJS += ../../WDL/jnetlib/connection.o
Added: trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-add-jack-with-fixes.patch
===================================================================
--- trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-add-jack-with-fixes.patch (rev 0)
+++ trunk/overlays/proaudio/media-sound/ninjam-cclient/files/ninjam-cclient-0.01a-add-jack-with-fixes.patch 2010-10-26 17:39:25 UTC (rev 1784)
@@ -0,0 +1,517 @@
+diff -Naru WDL.old/1 WDL/1
+--- WDL.old/1 1970-01-01 01:00:00.000000000 +0100
++++ WDL/1 2010-10-26 17:11:25.000000000 +0100
+@@ -0,0 +1,250 @@
++/*
++ WDL - wavwrite.h
++ Copyright (C) 2005 Cockos Incorporated
++
++ WDL is dual-licensed. You may modify and/or distribute WDL under either of
++ the following licenses:
++
++ This software is provided 'as-is', without any express or implied
++ warranty. In no event will the authors be held liable for any damages
++ arising from the use of this software.
++
++ Permission is granted to anyone to use this software for any purpose,
++ including commercial applications, and to alter it and redistribute it
++ freely, subject to the following restrictions:
++
++ 1. The origin of this software must not be misrepresented; you must not
++ claim that you wrote the original software. If you use this software
++ in a product, an acknowledgment in the product documentation would be
++ appreciated but is not required.
++ 2. Altered source versions must be plainly marked as such, and must not be
++ misrepresented as being the original software.
++ 3. This notice may not be removed or altered from any source distribution.
++
++
++ or:
++
++ WDL 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.
++
++ WDL 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 WDL; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++*/
++
++/*
++
++ This file provides a simple class for writing PCM WAV files.
++
++*/
++
++
++#ifndef _WAVWRITE_H_
++#define _WAVWRITE_H_
++
++
++#include <stdio.h>
++#include "pcmfmtcvt.h"
++
++class WaveWriter
++{
++ public:
++ // appending doesnt check sample types
++ WaveWriter()
++ {
++ m_fp=0;
++ m_bps=0;
++ m_srate=0;
++ m_nch=0;
++ }
++
++ WaveWriter(char *filename, int bps, int nch, int srate, int allow_append=1)
++ {
++ m_fp=0;
++ m_bps=0;
++ m_srate=0;
++ m_nch=0;
++ Open(filename,bps,nch,srate,allow_append);
++
++ }
++
++ int Open(char *filename, int bps, int nch, int srate, int allow_append=1)
++ {
++ m_fp=0;
++ if (allow_append)
++ {
++ m_fp=fopen(filename,"r+b");
++ if (m_fp)
++ {
++ fseek(m_fp,0,SEEK_END);
++ int pos=ftell(m_fp);
++ if (pos < 44)
++ {
++ char buf[44]={0,};
++ fwrite(buf,1,44-pos,m_fp);
++ }
++ }
++ }
++ if (!m_fp)
++ {
++ m_fp=fopen(filename,"wb");
++ char tbuf[44];
++ fwrite(tbuf,1,44,m_fp); // room for header
++ }
++ m_bps=bps;
++ m_nch=nch>1?2:1;
++ m_srate=srate;
++
++ return !!m_fp;
++ }
++
++ ~WaveWriter()
++ {
++ if (m_fp)
++ {
++ int bytelen=ftell(m_fp)-44;
++ fseek(m_fp,0,SEEK_SET);
++
++ // write header
++ fwrite("RIFF",1,4,m_fp);
++ int riff_size=bytelen+44-8;
++ int x;
++ for (x = 0; x < 32; x += 8)
++ {
++ unsigned char c=(riff_size>>x)&255;
++ fwrite(&c,1,1,m_fp);
++ }
++ fwrite("WAVEfmt \x10\0\0\0",1,12,m_fp);
++ fwrite("\1\0",1,2,m_fp); // PCM
++
++ for (x = 0; x < 16; x += 8) // nch
++ {
++ char c=(m_nch>>x)&255;
++ fwrite(&c,1,1,m_fp);
++ }
++ for (x = 0; x < 32; x += 8) // srate
++ {
++ char c=(m_srate>>x)&255;
++ fwrite(&c,1,1,m_fp);
++ }
++ for (x = 0; x < 32; x += 8) // bytes_per_sec
++ {
++ char c=((m_nch * (m_bps/8) * m_srate)>>x)&255;
++ fwrite(&c,1,1,m_fp);
++ }
++ int blockalign=m_nch * (m_bps/8);
++ for (x = 0; x < 16; x += 8) // block alignment
++ {
++ char c=(blockalign>>x)&255;
++ fwrite(&c,1,1,m_fp);
++ }
++ for (x = 0; x < 16; x += 8) // bits/sample
++ {
++ char c=((m_bps&~7)>>x)&255;
++ fwrite(&c,1,1,m_fp);
++ }
++ fwrite("data",1,4,m_fp);
++ for (x = 0; x < 32; x += 8) // size
++ {
++ char c=((bytelen)>>x)&255;
++ fwrite(&c,1,1,m_fp);
++ }
++
++ fclose(m_fp);
++ m_fp=0;
++ }
++ }
++
++ int Status() { return !!m_fp; }
++
++ void WriteRaw(void *buf, int len)
++ {
++ if (m_fp) fwrite(buf,1,len,m_fp);
++ }
++
++ void WriteFloats(float *samples, int nsamples)
++ {
++ if (!m_fp) return;
++
++ if (m_bps == 16)
++ {
++ while (nsamples-->0)
++ {
++ short a;
++ float_TO_INT16(a,*samples);
++ unsigned char c=a&0xff;
++ fwrite(&c,1,1,m_fp);
++ c=a>>8;
++ fwrite(&c,1,1,m_fp);
++ samples++;
++ }
++ }
++ else if (m_bps == 24)
++ {
++ while (nsamples-->0)
++ {
++ unsigned char a[3];
++ float_to_i24(samples,a);
++ fwrite(a,1,3,m_fp);
++ samples++;
++ }
++ }
++ }
++
++ void WriteFloatsNI(float **samples, int offs, int nsamples)
++ {
++ if (!m_fp) return;
++ float *tmpptrs[2]={samples[0]+offs,m_nch>1?samples[1]+offs:NULL};
++
++ if (m_bps == 16)
++ {
++ while (nsamples-->0)
++ {
++ int ch;
++ for (ch = 0; ch < m_nch; ch ++)
++ {
++ short a;
++ float_TO_INT16(a,tmpptrs[ch][0]);
++ unsigned char c=a&0xff;
++ fwrite(&c,1,1,m_fp);
++ c=a>>8;
++ fwrite(&c,1,1,m_fp);
++ tmpptrs[ch]++;
++ }
++ }
++ }
++ else if (m_bps == 24)
++ {
++ while (nsamples-->0)
++ {
++ int ch;
++ for (ch = 0; ch < m_nch; ch ++)
++ {
++ unsigned char a[3];
++ float_to_i24(tmpptrs[ch],a);
++ fwrite(a,1,3,m_fp);
++ tmpptrs[ch]++;
++ }
++ }
++ }
++ }
++
++ int get_nch() { return m_nch; }
++ int get_srate() { return m_srate; }
++ int get_bps() { return m_bps; }
++
++ private:
++ FILE *m_fp;
++ int m_bps,m_nch,m_srate;
++};
++
++
++#endif//_WAVWRITE_H
++_
+diff -Naru WDL.old/mutex.h WDL/mutex.h
+--- WDL.old/mutex.h 2005-08-30 04:33:10.000000000 +0100
++++ WDL/mutex.h 2010-10-26 17:11:25.000000000 +0100
+@@ -115,4 +115,5 @@
+
+ };
+
+-#endif
+\ No newline at end of file
++#endif
++
+diff -Naru WDL.old/pcmfmtcvt.h WDL/pcmfmtcvt.h
+--- WDL.old/pcmfmtcvt.h 2005-08-30 04:33:10.000000000 +0100
++++ WDL/pcmfmtcvt.h 2010-10-26 17:11:25.000000000 +0100
+@@ -402,4 +402,5 @@
+ }
+
+
+-#endif //_PCMFMTCVT_H_
+\ No newline at end of file
++#endif //_PCMFMTCVT_H_
++
+diff -Naru WDL.old/wavwrite.h WDL/wavwrite.h
+--- WDL.old/wavwrite.h 2005-08-30 04:33:10.000000000 +0100
++++ WDL/wavwrite.h 2010-10-26 17:11:25.000000000 +0100
+@@ -246,4 +246,5 @@
+ };
+
+
+-#endif//_WAVWRITE_H_
+\ No newline at end of file
++#endif//_WAVWRITE_H
++
+diff -Naru ninjam.old/audiostream.h ninjam/audiostream.h
+--- ninjam.old/audiostream.h 2005-08-30 04:21:04.000000000 +0100
++++ ninjam/audiostream.h 2010-10-26 17:12:20.000000000 +0100
+@@ -64,7 +64,7 @@
+ #ifdef _MAC
+ audioStreamer *create_audioStreamer_CoreAudio(char **dev, int srate, int nch, int bps, SPLPROC proc);
+ #else
+-audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc);
++audioStreamer *create_audioStreamer_JACK(char *cfg, SPLPROC proc);
+ #endif
+
+ #endif
+diff -Naru ninjam.old/audiostream_jack.cpp ninjam/audiostream_jack.cpp
+--- ninjam.old/audiostream_jack.cpp 1970-01-01 01:00:00.000000000 +0100
++++ ninjam/audiostream_jack.cpp 2010-10-26 17:12:20.000000000 +0100
+@@ -0,0 +1,142 @@
++/*
++ NINJAM - audiostream_alsa.cpp
++ Copyright (C) 2004-2005 Cockos Incorporated
++
++ NINJAM 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.
++
++ NINJAM 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 NINJAM; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++*/
++
++/*
++
++ This file implements a audioStreamer that uses ALSA.
++ It only exposes the following functions:
++
++ audioStreamer *create_audioStreamer_ALSA(char *cfg, SPLPROC proc);
++
++ cfg is a string that has a list of parameter/value pairs (space delimited)
++ for the config:
++ in - input device i.e. hw:0,0
++ out - output device i.e. hw:0,0
++ srate - sample rate i.e. 48000
++ bps - bits/sample i.e. 16
++ nch - channels i.e. 2
++ bsize - block size (bytes) i.e. 2048
++ nblock - number of blocks i.e. 16
++
++
++ (everything else in this file is used internally)
++
++*/
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++
++#include <signal.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <pthread.h>
++
++#include <jack/jack.h>
++
++#include "../WDL/pcmfmtcvt.h"
++
++#include "../WDL/ptrlist.h"
++#include "audiostream.h"
++
++static void audiostream_onunder() { }
++static void audiostream_onover() { }
++
++
++
++
++
++class audioStreamer_JACK : public audioStreamer
++{
++ public:
++ audioStreamer_JACK( char *cfg, SPLPROC proc );
++ ~audioStreamer_JACK();
++
++ int process( jack_nframes_t nframes );
++ const char *GetChannelName(int idx)
++ {
++ if (idx == 0) return "Left";
++ if (idx == 1) return "Right";
++ return NULL;
++ }
++ private:
++ jack_client_t *client;
++ jack_port_t *in1, *in2;
++ jack_port_t *out1, *out2;
++
++ SPLPROC splproc;
++};
++
++
++int
++process_cb( jack_nframes_t nframes, audioStreamer_JACK *as ) {
++ return as->process( nframes );
++}
++
++
++//////////////// ALSA driver
++audioStreamer_JACK::audioStreamer_JACK( char *cfg, SPLPROC proc)
++{
++
++ splproc = proc;
++
++ if ((client = jack_client_new ("ninjam")) == 0) {
++ fprintf (stderr, "jack server not running?\n");
++ exit(20);
++ }
++
++ jack_set_process_callback (client, (JackProcessCallback) process_cb, this);
++
++
++ out1 = jack_port_register (client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
++ out2 = jack_port_register (client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
++
++ in1 = jack_port_register (client, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
++ in2 = jack_port_register (client, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
++
++ if (jack_activate (client)) {
++ fprintf (stderr, "cannot activate client");
++ exit(20);
++ }
++}
++
++audioStreamer_JACK::~audioStreamer_JACK()
++{
++ jack_deactivate( client );
++ sleep(1);
++}
++
++int
++audioStreamer_JACK::process( jack_nframes_t nframes ) {
++ float *inports[2];
++ float *outports[2];
++
++ inports[0] = (float *) jack_port_get_buffer( in1, nframes );
++ inports[1] = (float *) jack_port_get_buffer( in2, nframes );
++ outports[0] = (float *) jack_port_get_buffer( out1, nframes );
++ outports[1] = (float *) jack_port_get_buffer( out2, nframes );
++
++ splproc( inports, 2, outports, 2, nframes, jack_get_sample_rate( client ) );
++ return 0;
++}
++
++audioStreamer *create_audioStreamer_JACK(char *cfg, SPLPROC proc)
++{
++ return new audioStreamer_JACK( cfg, proc);
++}
+diff -Naru ninjam.old/cursesclient/cursesclient.cpp ninjam/cursesclient/cursesclient.cpp
+--- ninjam.old/cursesclient/cursesclient.cpp 2005-08-30 04:59:43.000000000 +0100
++++ ninjam/cursesclient/cursesclient.cpp 2010-10-26 17:12:20.000000000 +0100
+@@ -1097,7 +1097,7 @@
+ #ifdef _MAC
+ g_audio=create_audioStreamer_CoreAudio(&dev_name_in,48000,2,16,audiostream_onsamples);
+ #else
+- g_audio=create_audioStreamer_ALSA(dev_name_in,audiostream_onsamples);
++ g_audio=create_audioStreamer_JACK(dev_name_in,audiostream_onsamples);
+ #endif
+ }
+ #endif
+diff -Naru ninjam.old/cursesclient/ninjam.config ninjam/cursesclient/ninjam.config
+--- ninjam.old/cursesclient/ninjam.config 1970-01-01 01:00:00.000000000 +0100
++++ ninjam/cursesclient/ninjam.config 2010-10-26 17:12:20.000000000 +0100
+@@ -0,0 +1,3 @@
++master mastervol 1.000000 masterpan 0.000000 metrovol 0.500000 metropan 0.000000 mastermute 0 metromute 1
++local 0 source 0 bc 1 mute 0 solo 0 volume 1.000000 pan 0.000000 jesus 0 name `hydrogen`
++local 1 source 1 bc 1 mute 0 solo 0 volume 1.000000 pan 0.000000 jesus 0 name `albino`
+diff -Naru ninjam.old/mpb.cpp ninjam/mpb.cpp
+--- ninjam.old/mpb.cpp 2005-08-30 04:16:06.000000000 +0100
++++ ninjam/mpb.cpp 2010-10-26 17:12:20.000000000 +0100
+@@ -886,4 +886,5 @@
+ }
+
+ return nm;
+-}
+\ No newline at end of file
++}
++
+diff -Naru ninjam.old/njmisc.cpp ninjam/njmisc.cpp
+--- ninjam.old/njmisc.cpp 2005-08-30 04:16:07.000000000 +0100
++++ ninjam/njmisc.cpp 2010-10-26 17:12:20.000000000 +0100
+@@ -152,4 +152,5 @@
+
+
+
+-#endif
+\ No newline at end of file
++#endif
++
+diff -Naru ninjam.old/njmisc.h ninjam/njmisc.h
+--- ninjam.old/njmisc.h 2005-08-30 04:16:07.000000000 +0100
++++ ninjam/njmisc.h 2010-10-26 17:12:20.000000000 +0100
+@@ -51,4 +51,5 @@
+
+ #endif
+
+-#endif
+\ No newline at end of file
++#endif
++
+--- ninjam.old/cursesclient/Makefile 2005-08-30 22:51:32.000000000 +0100
++++ ninjam/cursesclient/Makefile 2010-10-26 17:43:31.000000000 +0100
+@@ -9,7 +9,7 @@
+ LFLAGS = -framework coreaudio -lncurses.5 -lm
+ else
+ OPTFLAGS += -malign-double
+-LFLAGS = -lncurses -lm -lasound
++LFLAGS = -lncurses -lm -ljack
+ endif
+
+ #############################################################
+@@ -35,7 +35,7 @@
+ ifdef MAC
+ OBJS += ../audiostream_mac.o
+ else
+-OBJS += ../audiostream_alsa.o
++OBJS += ../audiostream_jack.o
+ endif
+
+ OBJS += ../njmisc.o
Modified: trunk/overlays/proaudio/media-sound/ninjam-cclient/ninjam-cclient-0.01a.ebuild
===================================================================
--- trunk/overlays/proaudio/media-sound/ninjam-cclient/ninjam-cclient-0.01a.ebuild 2010-10-25 20:00:24 UTC (rev 1783)
+++ trunk/overlays/proaudio/media-sound/ninjam-cclient/ninjam-cclient-0.01a.ebuild 2010-10-26 17:39:25 UTC (rev 1784)
@@ -1,8 +1,8 @@
-# Copyright 1999-2006 Gentoo Foundation
+# Copyright 1999-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
-inherit eutils
+inherit eutils toolchain-funcs
MY_P="cclient_src_v${PV}"
@@ -22,12 +22,19 @@
sys-libs/ncurses
media-libs/libogg
media-libs/libvorbis"
+RDEPEND="${DEPEND}"
src_compile() {
- epatch ${FILESDIR}/add-jack-with-fixes.patch
- emake || die "make failed"
+ epatch "${FILESDIR}/${P}-add-jack-with-fixes.patch"
+ epatch "${FILESDIR}/${P}-Makefile.patch"
+
+ cd ninjam/cursesclient || die "cd ninjam/cursesclient failed"
+
+ tc-export CC CXX
+ OPTFLAGS="${CXXFLAGS}" emake || die "make failed"
}
src_install() {
- dobin cninjam
+ cd ninjam/cursesclient || die "cd ninjam/cursesclient failed"
+ dobin cninjam || die
}