[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
 }


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/