Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first commit of new standalone SL

  • Loading branch information...
commit ed864dd9b006375e9e30cc6f54930c9fcae811f3 1 parent 06cbd43
@essej authored
View
52 configure.ac
@@ -1,13 +1,13 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(soop.cc)
+AC_INIT(src/engine.cpp)
AC_CONFIG_AUX_DIR(.)
-SOOP_MAJOR_VERSION=0
-SOOP_MINOR_VERSION=1
+SOOP_MAJOR_VERSION=1
+SOOP_MINOR_VERSION=0
SOOP_MICRO_VERSION=0
-BETA=
+BETA=dev
AC_SUBST(SOOP_MAJOR_VERSION)
AC_SUBST(SOOP_MINOR_VERSION)
@@ -21,7 +21,7 @@ AC_SUBST(SOOP_SO_VERSION)
AC_SUBST(SOOP_VERSION)
AC_SUBST(SOOP_RELEASE)
-AM_INIT_AUTOMAKE(soop,$SOOP_VERSION)
+AM_INIT_AUTOMAKE(sooperlooper,$SOOP_VERSION)
AM_CONFIG_HEADER(config.h)
dnl ====================================================================
@@ -31,7 +31,7 @@ dnl ====================================================================
AC_PROG_CC
AC_PROG_CXX
if test "$ac_cv_prog_cxx" = "no" ; then
- AC_MSG_ERROR([*** Ardour is written in C++. You don't appear to have a C++ compiler])
+ AC_MSG_ERROR([*** SooperLooper is written in C++. You don't appear to have a C++ compiler])
fi
CXXFLAGS="-g -D_REENTRANT"
@@ -53,21 +53,49 @@ AC_ARG_ENABLE(optimize,
# AC_MSG_ERROR([*** soop requires GTK+, but it doesn't appear to be installed])
#])
-PKG_CHECK_MODULES(JACK, jack >= 0.66.0)
-PKG_CHECK_MODULES(XML, libxml-2.0 >= 2.5)
+PKG_CHECK_MODULES(JACK, jack >= 0.80.0)
+AC_SUBST(JACK_LIBS)
+AC_SUBST(JACK_CFLAGS)
+
+
+#PKG_CHECK_MODULES(XML, libxml-2.0 >= 2.5)
+
+
PKG_CHECK_MODULES(GTKMM, gtkmm-2.0 >= 2.0)
+AC_SUBST(GTKMM_LIBS)
+AC_SUBST(GTKMM_CFLAGS)
+
+PKG_CHECK_MODULES(LOSC, liblo >= 0.5)
+AC_SUBST(LOSC_LIBS)
+AC_SUBST(LOSC_CFLAGS)
+
+dnl curses
+AC_CHECK_LIB(ncurses,initscr,have_ncurses=yes,[AC_MSG_WARN([******** you don't have the ncurses library correctly installed])])
+
+NCURSES_LIBS=-lncurses
+AC_SUBST(NCURSES_LIBS)
+
+dnl sigc++
+PKG_CHECK_MODULES(SIGCPP, sigc++-1.2 >= 0.14, have_sigc12=yes, have_sigc12=no)
+AC_SUBST(SIGCPP_LIBS)
+AC_SUBST(SIGCPP_CFLAGS)
+
-EXTRA_LIBS="$JACK_LIBS $XML_LIBS $GTKMM_LIBS"
+EXTRA_LIBS="$JACK_LIBS $XML_LIBS $GTKMM_LIBS $LOSC_LIBS $SIGCPP_LIBS"
AC_LANG_CPLUSPLUS
-CFLAGS="$CFLAGS -DSAMPLE_MEMORY=200 $GTKMM_CFLAGS $JACK_CFLAGS $XML_CFLAGS"
+CFLAGS="$CFLAGS -DSAMPLE_MEMORY=200 $GTKMM_CFLAGS $JACK_CFLAGS $LOSC_CFLAGS $SIGCPP_CFLAGS"
CXXFLAGS=$CFLAGS
-LIBS="$LIBS $EXTRA_LIBS"
+#LIBS="$LIBS $EXTRA_LIBS"
#CFLAGS="$CFLAGS -DSAMPLE_MEMORY=200 -I../ardour/libs/sigc++/sigc++/config -I../ardour/libs/sigc++ -I../ardour/libs/gtkmm -I../ardour/libs/gtkmm/gdk-- -I../ardour/libs/gtkmm/src $GTK_CFLAGS $JACK_CFLAGS $XML_CFLAGS"
#CXXFLAGS="$CXXFLAGS -DSAMPLE_MEMORY=200 -I../ardour/libs/sigc++/sigc++/config -I../ardour/libs/sigc++ -I../ardour/libs/gtkmm -I../ardour/libs/gtkmm/gdk-- -I../ardour/libs/gtkmm/src $GTK_CFLAGS $JACK_CFLAGS $XML_CFLAGS"
#LIBS="$LIBS -L../ardour/libs/gtkmm/gdk--/gdk-- -L../ardour/libs/sigc++/sigc++ -L../ardour/libs/gtkmm/src/gtk-- -lgtkmm -lgdkmm -lsigc $GTK_LIBS $JACK_LIBS $XML_LIBS $EXTRA_LIBS"
-AC_OUTPUT(Makefile)
+AC_OUTPUT([
+Makefile
+src/Makefile
+version.h
+])
View
110 src/Event.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * *
+ * LinuxSampler - modular, streaming capable sampler *
+ * *
+ * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
+ * MA 02111-1307 USA *
+ ***************************************************************************/
+
+#ifndef __LS_EVENT_H__
+#define __LS_EVENT_H__
+
+#include "../../common/global.h"
+
+namespace LinuxSampler {
+
+ // just symbol prototyping
+ class Event;
+
+ /**
+ * Generates Event objects and is responsible for resolving the position
+ * in the current audio fragment each Event actually belongs to.
+ */
+ class EventGenerator {
+ public:
+ EventGenerator(uint SampleRate);
+ void UpdateFragmentTime(uint SamplesToProcess);
+ Event CreateEvent();
+ protected:
+ typedef uint32_t time_stamp_t; ///< We read the processor's cycle count register as a reference for the real time. These are of course only abstract values with arbitrary time entity, but that's not a problem as we calculate relatively.
+ inline uint ToFragmentPos(time_stamp_t TimeStamp) {
+ return uint ((TimeStamp - FragmentTime.begin) * FragmentTime.sample_ratio);
+ }
+ friend class Event;
+ private:
+ uint uiSampleRate;
+ uint uiSamplesProcessed;
+ struct __FragmentTime__ {
+ time_stamp_t begin; ///< Real time stamp of the beginning of this audio fragment cycle.
+ time_stamp_t end; ///< Real time stamp of the end of this audio fragment cycle.
+ float sample_ratio; ///< (Samples per cycle) / (Real time duration of cycle)
+ } FragmentTime;
+ time_stamp_t CreateTimeStamp();
+ };
+
+ /**
+ * Events are usually caused by a MIDI source or an internal modulation
+ * controller like LFO or EG. An event can only be created by an
+ * EventGenerator.
+ *
+ * @see EventGenerator
+ */
+ class Event {
+ public:
+ Event(){}
+ enum type_t {
+ type_note_on,
+ type_note_off,
+ type_pitchbend,
+ type_control_change,
+ type_cancel_release, ///< transformed either from a note-on or sustain-pedal-down event
+ type_release ///< transformed either from a note-off or sustain-pedal-up event
+ } Type;
+ enum destination_t {
+ destination_vca, ///< Volume level
+ destination_vco, ///< Pitch depth
+ destination_vcfc, ///< Filter curoff frequency
+ destination_vcfr, ///< Filter resonance
+ destination_count ///< Total number of modulation destinations (this has to stay the last element in the enum)
+ };
+ union {
+ uint8_t Key; ///< MIDI key number for note-on and note-off events.
+ uint8_t Controller; ///< MIDI controller number for control change events.
+ };
+ union {
+ uint8_t Velocity; ///< Trigger or release velocity for note-on or note-off events.
+ uint8_t Value; ///< Value for control change events.
+ };
+ int16_t Pitch; ///< Pitch value for pitchbend events.
+
+ inline uint FragmentPos() {
+ if (iFragmentPos >= 0) return (uint) iFragmentPos;
+ return (uint) (iFragmentPos = pEventGenerator->ToFragmentPos(TimeStamp));
+ }
+ protected:
+ typedef EventGenerator::time_stamp_t time_stamp_t;
+ Event(EventGenerator* pGenerator, EventGenerator::time_stamp_t Time);
+ friend class EventGenerator;
+ private:
+ EventGenerator* pEventGenerator; ///< Creator of the event.
+ time_stamp_t TimeStamp; ///< Time stamp of the event's occurence.
+ int iFragmentPos; ///< Position in the current fragment this event refers to.
+ };
+
+} // namespace LinuxSampler
+
+#endif // __LS_EVENT_H__
View
28 src/Makefile.am
@@ -0,0 +1,28 @@
+bin_PROGRAMS = soop sooperlooper osctest
+
+soop_SOURCES = soop.cc plugin.cc
+
+soop_LDADD = @JACK_LIBS@ @GTKMM_LIBS@
+
+
+sooperlooper_SOURCES = \
+ sooperlooper.cpp \
+ engine.cpp \
+ control_osc.cpp \
+ looper.cpp \
+ plugin.cc \
+ event.cpp \
+ midi_bridge.cpp \
+ alsa_midi_bridge.cpp
+
+
+sooperlooper_LDADD = @JACK_LIBS@ @LOSC_LIBS@ @SIGCPP_LIBS@ -lasound
+
+
+osctest_SOURCES = osctest.cpp
+osctest_LDADD = @LOSC_LIBS@ @NCURSES_LIBS@ -lpthread
+
+
+noinst_HEADERS = $(wildcard *.hpp *.h)
+
+EXTRA_DIST = oxy8.slb midiwizard.slb
View
166 src/alsa_midi_bridge.cpp
@@ -0,0 +1,166 @@
+/*
+** Copyright (C) 2004 Jesse Chappell <jesse@essej.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+#include "alsa_midi_bridge.hpp"
+#include <pthread.h>
+
+using namespace SooperLooper;
+using namespace std;
+
+AlsaMidiBridge::AlsaMidiBridge (string name, string oscurl)
+ : MidiBridge (name, oscurl), _seq(0)
+{
+ _done = false;
+
+ if ((_seq = create_sequencer (name, true)) == 0) {
+ return;
+ }
+
+
+ pthread_create (&_midi_thread, NULL, &AlsaMidiBridge::_midi_receiver, this);
+}
+
+AlsaMidiBridge::~AlsaMidiBridge()
+{
+ stop_midireceiver();
+}
+
+snd_seq_t *
+AlsaMidiBridge::create_sequencer (string client_name, bool isinput)
+{
+ snd_seq_t * seq;
+ int err;
+
+ if ((err = snd_seq_open (&seq, "default", SND_SEQ_OPEN_DUPLEX, 0)) != 0) {
+ fprintf (stderr, "Could not open ALSA sequencer, aborting\n\n%s\n\n"
+ "Make sure you have configure ALSA properly and that\n"
+ "/proc/asound/seq/clients exists and contains relevant\n"
+ "devices (%s).",
+ snd_strerror (err));
+ return 0;
+ }
+
+ snd_seq_set_client_name (seq, client_name.c_str());
+
+ if ((err = snd_seq_create_simple_port (seq, isinput? "Input" : "Output",
+ (isinput? SND_SEQ_PORT_CAP_WRITE: SND_SEQ_PORT_CAP_READ)| SND_SEQ_PORT_CAP_DUPLEX |
+ SND_SEQ_PORT_CAP_SUBS_READ|SND_SEQ_PORT_CAP_SUBS_WRITE,
+ SND_SEQ_PORT_TYPE_APPLICATION|SND_SEQ_PORT_TYPE_SPECIFIC)) != 0) {
+ fprintf (stderr, "Could not create ALSA port: %s", snd_strerror (err));
+ snd_seq_close(seq);
+ return 0;
+ }
+
+ return seq;
+}
+
+
+void * AlsaMidiBridge::_midi_receiver(void *arg)
+{
+ AlsaMidiBridge * bridge = static_cast<AlsaMidiBridge*> (arg);
+
+ bridge->midi_receiver();
+ return 0;
+}
+
+void AlsaMidiBridge::midi_receiver()
+{
+ snd_seq_event_t *event;
+ int val;
+
+ while (!_done) {
+
+ snd_seq_event_input (_seq, &event);
+
+ if (_done) {
+ break;
+ }
+
+ switch(event->type){
+ case SND_SEQ_EVENT_NOTEON:
+ queue_midi(0x90+event->data.note.channel,event->data.note.note,event->data.note.velocity);
+ printf("Noteon, channel: %d note: %d vol: %d\n",event->data.note.channel,event->data.note.note,event->data.note.velocity);
+ break;
+ case SND_SEQ_EVENT_NOTEOFF:
+ queue_midi(0x90+event->data.note.channel,event->data.note.note,0);
+ printf("Noteoff, channel: %d note: %d vol: %d\n",event->data.note.channel,event->data.note.note,event->data.note.velocity);
+ break;
+ case SND_SEQ_EVENT_KEYPRESS:
+ //printf("Keypress, channel: %d note: %d vol: %d\n",event->data.note.channel,event->data.note.note,event->data.note.velocity);
+ queue_midi(0xa0+event->data.note.channel,event->data.note.note,event->data.note.velocity);
+ break;
+ case SND_SEQ_EVENT_CONTROLLER:
+ queue_midi(0xb0+event->data.control.channel,event->data.control.param,event->data.control.value);
+ printf("Control: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
+ break;
+ case SND_SEQ_EVENT_PITCHBEND:
+ val=event->data.control.value + 0x2000;
+ queue_midi(0xe0+event->data.control.channel,val&127,val>>7);
+ //printf("Pitch: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
+ break;
+ case SND_SEQ_EVENT_CHANPRESS:
+ //printf("chanpress: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
+ queue_midi(0xc0+event->data.control.channel,event->data.control.value,0);
+ break;
+ case SND_SEQ_EVENT_PGMCHANGE:
+ printf("pgmchange: %d %d %d\n",event->data.control.channel,event->data.control.param,event->data.control.value);
+ queue_midi(0xc0+event->data.control.channel,event->data.control.value,0);
+ break;
+ default:
+ //printf("Unknown type: %d\n",event->type);
+ break;
+ }
+ }
+
+}
+
+
+void AlsaMidiBridge::stop_midireceiver ()
+{
+ int err;
+ snd_seq_event_t event;
+ snd_seq_t *seq2 = create_sequencer ("slquit", true);
+
+
+ _done = true;
+
+ if (seq2 == 0) {
+ // oh well
+ return;
+ }
+
+ snd_seq_connect_to (seq2, 0, snd_seq_client_id (_seq),0);
+ snd_seq_ev_clear (&event);
+ snd_seq_ev_set_direct (&event);
+ snd_seq_ev_set_subs (&event);
+ snd_seq_ev_set_source (&event, 0);
+ snd_seq_ev_set_controller (&event,1,0x80,50);
+
+ if ((err = snd_seq_event_output (seq2, &event)) < 0) {
+ fprintf (stderr, "cannot send stop event to midi thread: %s\n",
+ snd_strerror (err));
+ }
+
+ snd_seq_drain_output (seq2);
+ snd_seq_close (seq2);
+ pthread_join (_midi_thread,NULL);
+ snd_seq_close (_seq);
+
+ _seq = 0;
+}
View
61 src/alsa_midi_bridge.hpp
@@ -0,0 +1,61 @@
+/*
+** Copyright (C) 2004 Jesse Chappell <jesse@essej.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+#ifndef __sooperlooper_alsa_midi_bridge__
+#define __sooperlooper_alsa_midi_bridge__
+
+#include "midi_bridge.hpp"
+
+#include <string>
+#include <alsa/asoundlib.h>
+#include <pthread.h>
+
+
+namespace SooperLooper {
+
+class AlsaMidiBridge
+ : public MidiBridge
+{
+ public:
+
+ AlsaMidiBridge (std::string name, std::string oscurl);
+ virtual ~AlsaMidiBridge();
+
+ virtual bool is_ok() {return _seq != 0;}
+
+ protected:
+
+ static void * _midi_receiver (void * arg);
+
+ void midi_receiver ();
+ void stop_midireceiver ();
+
+ snd_seq_t * create_sequencer (std::string client_name, bool isinput);
+
+
+ snd_seq_t * _seq;
+ pthread_t _midi_thread;
+
+ bool _done;
+};
+
+};
+
+
+#endif
View
1,236 src/atomic.h
@@ -0,0 +1,1236 @@
+/*
+ Copyright (C) 2001 Paul Davis and others (see below)
+ Code derived from various headers from the Linux kernel.
+ Copyright attributions maintained where present.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __libpbd_atomic_h__
+#define __libpbd_atomic_h__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h> /* config.h c/o auto* tools, wherever it may be */
+#endif
+
+#ifdef HAVE_SMP /* a macro we control, to manage ... */
+#define CONFIG_SMP /* ... the macro the kernel headers use */
+#endif
+
+#if defined(__powerpc__) || defined(__ppc__)
+
+/*
+ * BK Id: SCCS/s.atomic.h 1.15 10/28/01 10:37:22 trini
+ */
+/*
+ * PowerPC atomic operations
+ */
+
+#ifndef _ASM_PPC_ATOMIC_H_
+#define _ASM_PPC_ATOMIC_H_
+
+typedef struct { volatile int counter; } atomic_t;
+
+
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
+extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
+
+#ifdef CONFIG_SMP
+#define SMP_ISYNC "\n\tisync"
+#else
+#define SMP_ISYNC
+#endif
+
+static __inline__ void atomic_add(int a, atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%3\n\
+ add %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne- 1b"
+ : "=&r" (t), "=m" (v->counter)
+ : "r" (a), "r" (&v->counter), "m" (v->counter)
+ : "cc");
+}
+
+static __inline__ int atomic_add_return(int a, atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%2\n\
+ add %0,%1,%0\n\
+ stwcx. %0,0,%2\n\
+ bne- 1b"
+ SMP_ISYNC
+ : "=&r" (t)
+ : "r" (a), "r" (&v->counter)
+ : "cc", "memory");
+
+ return t;
+}
+
+static __inline__ void atomic_sub(int a, atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%3\n\
+ subf %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne- 1b"
+ : "=&r" (t), "=m" (v->counter)
+ : "r" (a), "r" (&v->counter), "m" (v->counter)
+ : "cc");
+}
+
+static __inline__ int atomic_sub_return(int a, atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%2\n\
+ subf %0,%1,%0\n\
+ stwcx. %0,0,%2\n\
+ bne- 1b"
+ SMP_ISYNC
+ : "=&r" (t)
+ : "r" (a), "r" (&v->counter)
+ : "cc", "memory");
+
+ return t;
+}
+
+static __inline__ void atomic_inc(atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%2\n\
+ addic %0,%0,1\n\
+ stwcx. %0,0,%2\n\
+ bne- 1b"
+ : "=&r" (t), "=m" (v->counter)
+ : "r" (&v->counter), "m" (v->counter)
+ : "cc");
+}
+
+static __inline__ int atomic_inc_return(atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%1\n\
+ addic %0,%0,1\n\
+ stwcx. %0,0,%1\n\
+ bne- 1b"
+ SMP_ISYNC
+ : "=&r" (t)
+ : "r" (&v->counter)
+ : "cc", "memory");
+
+ return t;
+}
+
+static __inline__ void atomic_dec(atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%2\n\
+ addic %0,%0,-1\n\
+ stwcx. %0,0,%2\n\
+ bne- 1b"
+ : "=&r" (t), "=m" (v->counter)
+ : "r" (&v->counter), "m" (v->counter)
+ : "cc");
+}
+
+static __inline__ int atomic_dec_return(atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%1\n\
+ addic %0,%0,-1\n\
+ stwcx. %0,0,%1\n\
+ bne- 1b"
+ SMP_ISYNC
+ : "=&r" (t)
+ : "r" (&v->counter)
+ : "cc", "memory");
+
+ return t;
+}
+
+#define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0)
+#define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0)
+
+/*
+ * Atomically test *v and decrement if it is greater than 0.
+ * The function returns the old value of *v minus 1.
+ */
+static __inline__ int atomic_dec_if_positive(atomic_t *v)
+{
+ int t;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%1\n\
+ addic. %0,%0,-1\n\
+ blt- 2f\n\
+ stwcx. %0,0,%1\n\
+ bne- 1b"
+ SMP_ISYNC
+ "\n\
+2:" : "=&r" (t)
+ : "r" (&v->counter)
+ : "cc", "memory");
+
+ return t;
+}
+
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
+
+#endif /* _ASM_PPC_ATOMIC_H_ */
+
+/***********************************************************************/
+
+# else /* !PPC */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifndef __ARCH_I386_ATOMIC__
+#define __ARCH_I386_ATOMIC__
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+#ifdef CONFIG_SMP
+#define SMP_LOCK "lock ; "
+#else
+#define SMP_LOCK ""
+#endif
+
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v) ((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v. Note that the guaranteed useful range
+ * of an atomic_t is only 24 bits.
+ */
+static __inline__ void atomic_add(int i, atomic_t *v)
+{
+ __asm__ __volatile__(
+ SMP_LOCK "addl %1,%0"
+ :"=m" (v->counter)
+ :"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ void atomic_sub(int i, atomic_t *v)
+{
+ __asm__ __volatile__(
+ SMP_LOCK "subl %1,%0"
+ :"=m" (v->counter)
+ :"ir" (i), "m" (v->counter));
+}
+
+/**
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ SMP_LOCK "subl %2,%0; sete %1"
+ :"=m" (v->counter), "=qm" (c)
+ :"ir" (i), "m" (v->counter) : "memory");
+ return c;
+}
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ void atomic_inc(atomic_t *v)
+{
+ __asm__ __volatile__(
+ SMP_LOCK "incl %0"
+ :"=m" (v->counter)
+ :"m" (v->counter));
+}
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ void atomic_dec(atomic_t *v)
+{
+ __asm__ __volatile__(
+ SMP_LOCK "decl %0"
+ :"=m" (v->counter)
+ :"m" (v->counter));
+}
+
+/**
+ * atomic_dec_and_test - decrement and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ SMP_LOCK "decl %0; sete %1"
+ :"=m" (v->counter), "=qm" (c)
+ :"m" (v->counter) : "memory");
+ return c != 0;
+}
+
+/**
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ int atomic_inc_and_test(atomic_t *v)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ SMP_LOCK "incl %0; sete %1"
+ :"=m" (v->counter), "=qm" (c)
+ :"m" (v->counter) : "memory");
+ return c != 0;
+}
+
+/**
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+static __inline__ int atomic_add_negative(int i, atomic_t *v)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ SMP_LOCK "addl %2,%0; sets %1"
+ :"=m" (v->counter), "=qm" (c)
+ :"ir" (i), "m" (v->counter) : "memory");
+ return c;
+}
+
+/* These are x86-specific, used by some header files */
+#define atomic_clear_mask(mask, addr) \
+__asm__ __volatile__(SMP_LOCK "andl %0,%1" \
+: : "r" (~(mask)),"m" (*addr) : "memory")
+
+#define atomic_set_mask(mask, addr) \
+__asm__ __volatile__(SMP_LOCK "orl %0,%1" \
+: : "r" (mask),"m" (*addr) : "memory")
+
+/* Atomic operations are already serializing on x86 */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#endif /* __ARCH_I386_ATOMIC__ */
+
+/***********************************************************************/
+
+#else /* !PPC && !i386 */
+
+#ifdef __sparc__
+
+/* atomic.h: These still suck, but the I-cache hit rate is higher.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au)
+ */
+
+#ifndef __ARCH_SPARC_ATOMIC__
+#define __ARCH_SPARC_ATOMIC__
+
+typedef struct { volatile int counter; } atomic_t;
+
+#ifndef CONFIG_SMP
+
+#define ATOMIC_INIT(i) { (i) }
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v, i) (((v)->counter) = i)
+
+#else
+/* We do the bulk of the actual work out of line in two common
+ * routines in assembler, see arch/sparc/lib/atomic.S for the
+ * "fun" details.
+ *
+ * For SMP the trick is you embed the spin lock byte within
+ * the word, use the low byte so signedness is easily retained
+ * via a quick arithmetic shift. It looks like this:
+ *
+ * ----------------------------------------
+ * | signed 24-bit counter value | lock | atomic_t
+ * ----------------------------------------
+ * 31 8 7 0
+ */
+
+#define ATOMIC_INIT(i) { (i << 8) }
+
+static __inline__ int atomic_read(atomic_t *v)
+{
+ int ret = v->counter;
+
+ while(ret & 0xff)
+ ret = v->counter;
+
+ return ret >> 8;
+}
+
+#define atomic_set(v, i) (((v)->counter) = ((i) << 8))
+#endif
+
+static __inline__ int __atomic_add(int i, atomic_t *v)
+{
+ register volatile int *ptr asm("g1");
+ register int increment asm("g2");
+
+ ptr = &v->counter;
+ increment = i;
+
+ __asm__ __volatile__(
+ "mov %%o7, %%g4\n\t"
+ "call ___atomic_add\n\t"
+ " add %%o7, 8, %%o7\n"
+ : "=&r" (increment)
+ : "0" (increment), "r" (ptr)
+ : "g3", "g4", "g7", "memory", "cc");
+
+ return increment;
+}
+
+static __inline__ int __atomic_sub(int i, atomic_t *v)
+{
+ register volatile int *ptr asm("g1");
+ register int increment asm("g2");
+
+ ptr = &v->counter;
+ increment = i;
+
+ __asm__ __volatile__(
+ "mov %%o7, %%g4\n\t"
+ "call ___atomic_sub\n\t"
+ " add %%o7, 8, %%o7\n"
+ : "=&r" (increment)
+ : "0" (increment), "r" (ptr)
+ : "g3", "g4", "g7", "memory", "cc");
+
+ return increment;
+}
+
+#define atomic_add(i, v) ((void)__atomic_add((i), (v)))
+#define atomic_sub(i, v) ((void)__atomic_sub((i), (v)))
+
+#define atomic_dec_return(v) __atomic_sub(1, (v))
+#define atomic_inc_return(v) __atomic_add(1, (v))
+
+#define atomic_sub_and_test(i, v) (__atomic_sub((i), (v)) == 0)
+#define atomic_dec_and_test(v) (__atomic_sub(1, (v)) == 0)
+
+#define atomic_inc(v) ((void)__atomic_add(1, (v)))
+#define atomic_dec(v) ((void)__atomic_sub(1, (v)))
+
+#define atomic_add_negative(i, v) (__atomic_add((i), (v)) < 0)
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+
+#endif /* !(__ARCH_SPARC_ATOMIC__) */
+
+/***********************************************************************/
+
+#else
+
+#ifdef __ia64__
+
+#ifndef __ARCH_IA64_ATOMIC__
+#define __ARCH_IA64_ATOMIC__
+
+typedef volatile int atomic_t;
+
+inline
+int
+atomic_read (const atomic_t * a)
+{
+ return *a;
+}
+
+inline
+void
+atomic_set(atomic_t *a, int v)
+{
+ *a = v;
+}
+
+inline
+void
+atomic_inc (atomic_t *v)
+{
+ int old, r;
+
+ do {
+ old = atomic_read(v);
+ __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO" (old));
+ __asm__ __volatile__ ("cmpxchg4.acq %0=[%1],%2,ar.ccv"
+ : "=r"(r) : "r"(v), "r"(old + 1)
+ : "memory");
+ } while (r != old);
+}
+
+inline
+void
+atomic_dec (atomic_t *v)
+{
+ int old, r;
+
+ do {
+ old = atomic_read(v);
+ __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO" (old));
+ __asm__ __volatile__ ("cmpxchg4.acq %0=[%1],%2,ar.ccv"
+ : "=r"(r) : "r"(v), "r"(old - 1)
+ : "memory");
+ } while (r != old);
+}
+
+inline
+int
+atomic_dec_and_test (atomic_t *v)
+{
+ int old, r;
+
+ do {
+ old = atomic_read(v);
+ __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO" (old));
+ __asm__ __volatile__ ("cmpxchg4.acq %0=[%1],%2,ar.ccv"
+ : "=r"(r) : "r"(v), "r"(old - 1)
+ : "memory");
+ } while (r != old);
+ return old != 1;
+}
+
+#endif /* !(__ARCH_IA64_ATOMIC__) */
+
+#else
+
+#ifdef __alpha__
+
+#ifndef _ALPHA_ATOMIC_H
+#define _ALPHA_ATOMIC_H
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc...
+ *
+ * But use these as seldom as possible since they are much slower
+ * than regular operations.
+ */
+
+
+/*
+ * Counter is volatile to make sure gcc doesn't try to be clever
+ * and move things around on us. We need to use _exactly_ the address
+ * the user gave us, not some alias that contains the same information.
+ */
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) ( (atomic_t) { (i) } )
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v,i) ((v)->counter = (i))
+
+/*
+ * To get proper branch prediction for the main line, we must branch
+ * forward to code at the end of this object's .text section, then
+ * branch back to restart the operation.
+ */
+
+static __inline__ void atomic_add(int i, atomic_t * v)
+{
+ unsigned long temp;
+ __asm__ __volatile__(
+ "1: ldl_l %0,%1\n"
+ " addl %0,%2,%0\n"
+ " stl_c %0,%1\n"
+ " beq %0,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (v->counter)
+ :"Ir" (i), "m" (v->counter));
+}
+
+static __inline__ void atomic_sub(int i, atomic_t * v)
+{
+ unsigned long temp;
+ __asm__ __volatile__(
+ "1: ldl_l %0,%1\n"
+ " subl %0,%2,%0\n"
+ " stl_c %0,%1\n"
+ " beq %0,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (v->counter)
+ :"Ir" (i), "m" (v->counter));
+}
+
+/*
+ * Same as above, but return the result value
+ */
+static __inline__ long atomic_add_return(int i, atomic_t * v)
+{
+ long temp, result;
+ __asm__ __volatile__(
+ "1: ldl_l %0,%1\n"
+ " addl %0,%3,%2\n"
+ " addl %0,%3,%0\n"
+ " stl_c %0,%1\n"
+ " beq %0,2f\n"
+ " mb\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (v->counter), "=&r" (result)
+ :"Ir" (i), "m" (v->counter) : "memory");
+ return result;
+}
+
+static __inline__ long atomic_sub_return(int i, atomic_t * v)
+{
+ long temp, result;
+ __asm__ __volatile__(
+ "1: ldl_l %0,%1\n"
+ " subl %0,%3,%2\n"
+ " subl %0,%3,%0\n"
+ " stl_c %0,%1\n"
+ " beq %0,2f\n"
+ " mb\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (v->counter), "=&r" (result)
+ :"Ir" (i), "m" (v->counter) : "memory");
+ return result;
+}
+
+#define atomic_dec_return(v) atomic_sub_return(1,(v))
+#define atomic_inc_return(v) atomic_add_return(1,(v))
+
+#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+
+#define atomic_inc(v) atomic_add(1,(v))
+#define atomic_dec(v) atomic_sub(1,(v))
+
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
+
+#endif /* _ALPHA_ATOMIC_H */
+
+#else
+
+#ifdef __s390__
+
+#ifndef __ARCH_S390_ATOMIC__
+#define __ARCH_S390_ATOMIC__
+
+/*
+ * include/asm-s390/atomic.h
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Denis Joseph Barrow
+ *
+ * Derived from "include/asm-i386/bitops.h"
+ * Copyright (C) 1992, Linus Torvalds
+ *
+ */
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ * S390 uses 'Compare And Swap' for atomicity in SMP enviroment
+ */
+
+typedef struct { volatile int counter; } __attribute__ ((aligned (4))) atomic_t;
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_eieio() __asm__ __volatile__ ("BCR 15,0")
+
+#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string) \
+ __asm__ __volatile__(" l %0,0(%2)\n" \
+ "0: lr %1,%0\n" \
+ op_string " %1,%3\n" \
+ " cs %0,%1,0(%2)\n" \
+ " jl 0b" \
+ : "=&d" (old_val), "=&d" (new_val) \
+ : "a" (ptr), "d" (op_val) : "cc" );
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v,i) (((v)->counter) = (i))
+
+static __inline__ void atomic_add(int i, atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
+}
+
+static __inline__ int atomic_add_return (int i, atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
+ return new_val;
+}
+
+static __inline__ int atomic_add_negative(int i, atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
+ return new_val < 0;
+}
+
+static __inline__ void atomic_sub(int i, atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "sr");
+}
+
+static __inline__ void atomic_inc(volatile atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
+}
+
+static __inline__ int atomic_inc_return(volatile atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
+ return new_val;
+}
+
+static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
+ return new_val != 0;
+}
+
+static __inline__ void atomic_dec(volatile atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
+}
+
+static __inline__ int atomic_dec_return(volatile atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
+ return new_val;
+}
+
+static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
+ return new_val == 0;
+}
+
+static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, ~mask, "nr");
+}
+
+static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
+{
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, mask, "or");
+}
+
+/*
+ returns 0 if expected_oldval==value in *v ( swap was successful )
+ returns 1 if unsuccessful.
+*/
+static __inline__ int
+atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
+{
+ int retval;
+
+ __asm__ __volatile__(
+ " lr 0,%2\n"
+ " cs 0,%3,0(%1)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ "0:"
+ : "=&d" (retval)
+ : "a" (v), "d" (expected_oldval) , "d" (new_val)
+ : "0", "cc");
+ return retval;
+}
+
+/*
+ Spin till *v = expected_oldval then swap with newval.
+ */
+static __inline__ void
+atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
+{
+ __asm__ __volatile__(
+ "0: lr 0,%1\n"
+ " cs 0,%2,0(%0)\n"
+ " jl 0b\n"
+ : : "a" (v), "d" (expected_oldval) , "d" (new_val)
+ : "cc", "0" );
+}
+
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
+
+#endif /* __ARCH_S390_ATOMIC __ */
+
+#else
+
+#ifdef __mips__
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ *
+ * But use these as seldom as possible since they are much more slower
+ * than regular operations.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996, 1997, 2000 by Ralf Baechle
+ */
+#ifndef __ASM_ATOMIC_H
+#define __ASM_ATOMIC_H
+
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) { (i) }
+
+/*
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v) ((v)->counter)
+
+/*
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v,i) ((v)->counter = (i))
+
+/*
+ * ... while for MIPS II and better we can use ll/sc instruction. This
+ * implementation is SMP safe ...
+ */
+
+/*
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v. Note that the guaranteed useful range
+ * of an atomic_t is only 24 bits.
+ */
+extern __inline__ void atomic_add(int i, atomic_t * v)
+{
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ ".set push # atomic_add\n"
+ ".set mips2 \n"
+ "1: ll %0, %1 \n"
+ " addu %0, %2 \n"
+ " sc %0, %1 \n"
+ " beqz %0, 1b \n"
+ ".set pop \n"
+ : "=&r" (temp), "=m" (v->counter)
+ : "Ir" (i), "m" (v->counter));
+}
+
+/*
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+extern __inline__ void atomic_sub(int i, atomic_t * v)
+{
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ ".set push # atomic_sub\n"
+ ".set mips2 \n"
+ "1: ll %0, %1 \n"
+ " subu %0, %2 \n"
+ " sc %0, %1 \n"
+ " beqz %0, 1b \n"
+ ".set pop \n"
+ : "=&r" (temp), "=m" (v->counter)
+ : "Ir" (i), "m" (v->counter));
+}
+
+/*
+ * Same as above, but return the result value
+ */
+extern __inline__ int atomic_add_return(int i, atomic_t * v)
+{
+ unsigned long temp, result;
+
+ __asm__ __volatile__(
+ ".set push # atomic_add_return\n"
+ ".set mips2 \n"
+ ".set noreorder \n"
+ "1: ll %1, %2 \n"
+ " addu %0, %1, %3 \n"
+ " sc %0, %2 \n"
+ " beqz %0, 1b \n"
+ " addu %0, %1, %3 \n"
+ " sync \n"
+ ".set pop \n"
+ : "=&r" (result), "=&r" (temp), "=m" (v->counter)
+ : "Ir" (i), "m" (v->counter)
+ : "memory");
+
+ return result;
+}
+
+extern __inline__ int atomic_sub_return(int i, atomic_t * v)
+{
+ unsigned long temp, result;
+
+ __asm__ __volatile__(
+ ".set push # atomic_sub_return\n"
+ ".set mips2 \n"
+ ".set noreorder \n"
+ "1: ll %1, %2 \n"
+ " subu %0, %1, %3 \n"
+ " sc %0, %2 \n"
+ " beqz %0, 1b \n"
+ " subu %0, %1, %3 \n"
+ " sync \n"
+ ".set pop \n"
+ : "=&r" (result), "=&r" (temp), "=m" (v->counter)
+ : "Ir" (i), "m" (v->counter)
+ : "memory");
+
+ return result;
+}
+
+#define atomic_dec_return(v) atomic_sub_return(1,(v))
+#define atomic_inc_return(v) atomic_add_return(1,(v))
+
+/*
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
+
+/*
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0)
+
+/*
+ * atomic_dec_and_test - decrement by 1 and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+
+/*
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_inc(v) atomic_add(1,(v))
+
+/*
+ * atomic_dec - decrement and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_dec(v) atomic_sub(1,(v))
+
+/*
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero. Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ *
+ * Currently not implemented for MIPS.
+ */
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
+
+#endif /* __ASM_ATOMIC_H */
+
+#else
+
+#if defined(__m68k__)
+
+#ifndef __ARCH_M68K_ATOMIC__
+#define __ARCH_M68K_ATOMIC__
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ */
+
+/*
+ * We do not have SMP m68k systems, so we don't have to deal with that.
+ */
+
+typedef struct { int counter; } atomic_t;
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v, i) (((v)->counter) = i)
+
+static __inline__ void atomic_add(int i, atomic_t *v)
+{
+ __asm__ __volatile__("addl %1,%0" : "=m" (*v) : "id" (i), "0" (*v));
+}
+
+static __inline__ void atomic_sub(int i, atomic_t *v)
+{
+ __asm__ __volatile__("subl %1,%0" : "=m" (*v) : "id" (i), "0" (*v));
+}
+
+static __inline__ void atomic_inc(volatile atomic_t *v)
+{
+ __asm__ __volatile__("addql #1,%0" : "=m" (*v): "0" (*v));
+}
+
+static __inline__ void atomic_dec(volatile atomic_t *v)
+{
+ __asm__ __volatile__("subql #1,%0" : "=m" (*v): "0" (*v));
+}
+
+static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
+{
+ char c;
+ __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "=m" (*v): "1" (*v));
+ return c != 0;
+}
+
+#define atomic_clear_mask(mask, v) \
+ __asm__ __volatile__("andl %1,%0" : "=m" (*v) : "id" (~(mask)),"0"(*v))
+
+#define atomic_set_mask(mask, v) \
+ __asm__ __volatile__("orl %1,%0" : "=m" (*v) : "id" (mask),"0"(*v))
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#endif /* __ARCH_M68K_ATOMIC __ */
+
+#else
+
+#warning libs/pbd has no implementation of strictly atomic operations for your hardware.
+
+#define __NO_STRICT_ATOMIC
+#ifdef __NO_STRICT_ATOMIC
+
+/*
+ * Because the implementations from the kernel (where all these come
+ * from) use cli and spinlocks for hppa and arm...
+ */
+
+typedef struct { volatile int counter; } atomic_t;
+
+#define ATOMIC_INIT(i) ( (atomic_t) { (i) } )
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v,i) ((v)->counter = (i))
+
+static __inline__ void atomic_inc(atomic_t *v)
+{
+ v->counter++;
+}
+
+static __inline__ void atomic_dec(atomic_t *v)
+{
+ v->counter--;
+}
+
+static __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+ int res;
+ v->counter--;
+ res = v->counter;
+ return res == 0;
+}
+
+static __inline__ int atomic_inc_and_test(atomic_t *v)
+{
+ int res;
+ v->counter++;
+ res = v->counter;
+ return res == 0;
+}
+
+# endif /* __NO_STRICT_ATOMIC */
+# endif /* m68k */
+# endif /* mips */
+# endif /* s390 */
+# endif /* alpha */
+# endif /* ia64 */
+# endif /* sparc */
+# endif /* i386 */
+# endif /* ppc */
+
+#endif /* __libpbd_atomic_h__ */
+
View
416 src/control_osc.cpp
@@ -0,0 +1,416 @@
+/*
+** Copyright (C) 2004 Jesse Chappell <jesse@essej.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+#include <iostream>
+#include <cstdio>
+
+#include "control_osc.hpp"
+#include "engine.hpp"
+#include "ringbuffer.hpp"
+
+#include <lo/lo.h>
+#include <sigc++/sigc++.h>
+using namespace SigC;
+
+using namespace SooperLooper;
+using namespace std;
+
+static void error_callback(int num, const char *m, const char *path)
+{
+ fprintf(stderr, "liblo server error %d in path %s: %s\n", num, path, m);
+}
+
+
+
+ControlOSC::ControlOSC(Engine * eng, unsigned int port)
+ : _engine(eng), _port(port)
+{
+ char tmpstr[255];
+
+ _ok = false;
+
+ for (int j=0; j < 20; ++j) {
+ snprintf(tmpstr, sizeof(tmpstr), "%d", _port);
+
+ if ((_sthread = lo_server_thread_new(tmpstr, error_callback))) {
+ break;
+ }
+
+ cerr << "can't get osc at port: " << _port << endl;
+ _port++;
+ continue;
+ }
+
+ if (!_sthread) {
+ return;
+ }
+
+
+ _engine->LoopAdded.connect(slot (*this, &ControlOSC::on_loop_added));
+ _engine->LoopRemoved.connect(slot (*this, &ControlOSC::on_loop_removed));
+
+ on_loop_added (-1); // to match all
+
+ /* add method that will match the path /quit with no args */
+ lo_server_thread_add_method(_sthread, "/quit", "", ControlOSC::_quit_handler, this);
+
+ // lo_server_thread_add_method(_sthread, NULL, NULL, ControlOSC::_dummy_handler, this);
+
+
+
+ lo_server_thread_start(_sthread);
+
+ _ok = true;
+}
+
+ControlOSC::~ControlOSC()
+{
+ // stop server thread?? how?
+
+// if (_sthread) {
+// // this will block
+// lo_server_thread_stop (_sthread);
+// }
+}
+
+void
+ControlOSC::on_loop_added (int instance)
+{
+ char tmpstr[255];
+ cerr << "loop added: " << instance << endl;
+
+ snprintf(tmpstr, sizeof(tmpstr), "/sl/%d/down", instance);
+ lo_server_thread_add_method(_sthread, tmpstr, "s", ControlOSC::_updown_handler, new CommandInfo(this, instance, Event::type_cmd_down));
+
+ snprintf(tmpstr, sizeof(tmpstr), "/sl/%d/up", instance);
+ lo_server_thread_add_method(_sthread, tmpstr, "s", ControlOSC::_updown_handler, new CommandInfo(this, instance, Event::type_cmd_up));
+
+ snprintf(tmpstr, sizeof(tmpstr), "/sl/%d/set", instance);
+ lo_server_thread_add_method(_sthread, tmpstr, "sf", ControlOSC::_set_handler, new CommandInfo(this, instance, Event::type_control_change));
+
+ snprintf(tmpstr, sizeof(tmpstr), "/sl/%d/get", instance);
+ lo_server_thread_add_method(_sthread, tmpstr, "sss", ControlOSC::_get_handler, new CommandInfo(this, instance, Event::type_control_request));
+
+}
+
+void
+ControlOSC::on_loop_removed ()
+{
+
+
+}
+
+
+std::string
+ControlOSC::get_server_url()
+{
+ string url;
+ char * urlstr;
+
+ if (_sthread) {
+ urlstr = lo_server_thread_get_url (_sthread);
+ url = urlstr;
+ free (urlstr);
+ }
+
+ return url;
+}
+
+
+
+/* STATIC callbacks */
+
+int ControlOSC::_dummy_handler(const char *path, const char *types, lo_arg **argv, int argc,
+ void *data, void *user_data)
+{
+ cerr << "got path: " << path << endl;
+ return 0;
+}
+
+
+int ControlOSC::_quit_handler(const char *path, const char *types, lo_arg **argv, int argc,
+ void *data, void *user_data)
+{
+ ControlOSC * osc = static_cast<ControlOSC*> (user_data);
+ return osc->quit_handler (path, types, argv, argc, data);
+
+}
+
+int ControlOSC::_updown_handler(const char *path, const char *types, lo_arg **argv, int argc,
+ void *data, void *user_data)
+{
+ CommandInfo * cp = static_cast<CommandInfo*> (user_data);
+ return cp->osc->updown_handler (path, types, argv, argc, data, cp);
+}
+
+int ControlOSC::_set_handler(const char *path, const char *types, lo_arg **argv, int argc,
+ void *data, void *user_data)
+{
+ CommandInfo * cp = static_cast<CommandInfo*> (user_data);
+ return cp->osc->set_handler (path, types, argv, argc, data, cp);
+}
+
+int ControlOSC::_get_handler(const char *path, const char *types, lo_arg **argv, int argc,
+ void *data, void *user_data)
+{
+ CommandInfo * cp = static_cast<CommandInfo*> (user_data);
+ return cp->osc->get_handler (path, types, argv, argc, data, cp);
+}
+
+
+/* real callbacks */
+
+int ControlOSC::quit_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data)
+{
+ cerr << "got quit!" << endl;
+ _engine->quit();
+ return 0;
+}
+
+int ControlOSC::updown_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, CommandInfo *info)
+{
+ cerr << "updown " << path << " " << info->type << endl;
+
+ // first arg is a string
+
+ string cmd(&argv[0]->s);
+
+ _engine->push_command_event(info->type, to_command_t(cmd), info->instance);
+
+ return 0;
+}
+
+
+int ControlOSC::set_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, CommandInfo *info)
+{
+ cerr << "set " << path << endl;
+
+ // first arg is a control string, 2nd is float val
+
+ string ctrl(&argv[0]->s);
+ float val = argv[1]->f;
+
+ _engine->push_control_event(info->type, to_control_t(ctrl), val, info->instance);
+
+ return 0;
+
+}
+
+int ControlOSC::get_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, CommandInfo *info)
+{
+ // cerr << "get " << path << endl;
+
+ // todo, push this onto a queue for another thread to return
+
+ // first arg is control string, 2nd is return URL string 3rd is retpath
+ string ctrl (&argv[0]->s);
+ string returl (&argv[1]->s);
+ string retpath (&argv[2]->s);
+ lo_address addr;
+
+ if (_retaddr_map.find(returl) == _retaddr_map.end()) {
+ addr = lo_address_new_from_url (returl.c_str());
+ if (lo_address_errno (addr) < 0) {
+ fprintf(stderr, "addr error %d: %s\n", lo_address_errno(addr), lo_address_errstr(addr));
+ }
+ _retaddr_map[returl] = addr;
+ }
+ else {
+ addr = _retaddr_map[returl];
+ }
+
+
+
+ float val = _engine->get_control_value (to_control_t(ctrl), info->instance);
+
+ // cerr << "sending to " << returl << " path: " << retpath << " ctrl: " << ctrl << " val: " << val << endl;
+ if (lo_send(addr, retpath.c_str(), "sf", ctrl.c_str(), val) == -1) {
+ fprintf(stderr, "OSC error %d: %s\n", lo_address_errno(addr), lo_address_errstr(addr));
+ }
+
+ return 0;
+}
+
+
+Event::command_t ControlOSC::to_command_t (std::string cmd)
+{
+ if (cmd == "record") {
+ return Event::RECORD;
+ }
+ else if (cmd == "overdub") {
+ return Event::OVERDUB;
+ }
+ else if (cmd == "multiply") {
+ return Event::MULTIPLY;
+ }
+ else if (cmd == "insert") {
+ return Event::INSERT;
+ }
+ else if (cmd == "replace") {
+ return Event::REPLACE;
+ }
+ else if (cmd == "reverse") {
+ return Event::REVERSE;
+ }
+ else if (cmd == "mute") {
+ return Event::MUTE;
+ }
+ else if (cmd == "undo") {
+ return Event::UNDO;
+ }
+ else if (cmd == "redo") {
+ return Event::REDO;
+ }
+ else if (cmd == "scratch") {
+ return Event::SCRATCH;
+ }
+ else {
+ return Event::UNKNOWN;
+ }
+}
+
+std::string ControlOSC::to_command_str (Event::command_t cmd)
+{
+ switch (cmd)
+ {
+ case Event::RECORD:
+ return "record";
+ case Event::OVERDUB:
+ return "overdub";
+ case Event::MULTIPLY:
+ return "multiply";
+ case Event::INSERT:
+ return "insert";
+ case Event::REPLACE:
+ return "replace";
+ case Event::REVERSE:
+ return "reverse";
+ case Event::MUTE:
+ return "mute";
+ case Event::UNDO:
+ return "undo";
+ case Event::REDO:
+ return "redo";
+ case Event::SCRATCH:
+ return "scratch";
+
+ default:
+ return "unknown";
+ }
+}
+
+
+Event::control_t
+ControlOSC::to_control_t (std::string cmd)
+{
+ if (cmd == "rec_thresh") {
+ return Event::TriggerThreshold;
+ }
+ else if (cmd == "feedback") {
+ return Event::Feedback;
+ }
+ else if (cmd == "dry") {
+ return Event::DryLevel;
+ }
+ else if (cmd == "wet") {
+ return Event::WetLevel;
+ }
+ else if (cmd == "rate") {
+ return Event::Rate;
+ }
+ else if (cmd == "scratch_pos") {
+ return Event::ScratchPosition;
+ }
+ else if (cmd == "tap_trigger") {
+ return Event::TapDelayTrigger;
+ }
+ else if (cmd == "quantize") {
+ return Event::Quantize;
+ }
+ else if (cmd == "round") {
+ return Event::Round;
+ }
+ else if (cmd == "redo_is_tap") {
+ return Event::RedoTap;
+ }
+ // the output ones
+ else if (cmd == "state") {
+ return Event::State;
+ }
+ else if (cmd == "loop_len") {
+ return Event::LoopLength;
+ }
+ else if (cmd == "loop_pos") {
+ return Event::LoopPosition;
+ }
+ else if (cmd == "cycle_len") {
+ return Event::CycleLength;
+ }
+ else if (cmd == "free_time") {
+ return Event::FreeTime;
+ }
+ else if (cmd == "total_time") {
+ return Event::TotalTime;
+ }
+
+}
+
+std::string
+ControlOSC::to_control_str (Event::control_t cmd)
+{
+ switch (cmd)
+ {
+ case Event::TriggerThreshold:
+ return "rec_thresh";
+ case Event::DryLevel:
+ return "dry";
+ case Event::WetLevel:
+ return "wet";
+ case Event::Feedback:
+ return "feedback";
+ case Event::Rate:
+ return "rate";
+ case Event::ScratchPosition:
+ return "scratch_pos";
+ case Event::TapDelayTrigger:
+ return "tap_trigger";
+ case Event::Quantize:
+ return "quantize";
+ case Event::Round:
+ return "round";
+ case Event::RedoTap:
+ return "redo_is_tap";
+
+ case Event::State:
+ return "state";
+ case Event::LoopLength:
+ return "loop_len";
+ case Event::LoopPosition:
+ return "loop_pos";
+ case Event::CycleLength:
+ return "cycle_len";
+ case Event::FreeTime:
+ return "free_time";
+ case Event::TotalTime:
+ return "total_time";
+
+ default:
+ return "unknown";
+ }
+}
View
97 src/control_osc.hpp
@@ -0,0 +1,97 @@
+/*
+** Copyright (C) 2004 Jesse Chappell <jesse@essej.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+#ifndef __sooperlooper_control_osc__
+#define __sooperlooper_control_osc__
+
+
+#include <lo/lo.h>
+#include <string>
+#include <map>
+#include <sigc++/object.h>
+
+#include "event.hpp"
+
+namespace SooperLooper {
+
+class Engine;
+
+class ControlOSC
+ : public SigC::Object
+{
+ public:
+
+ ControlOSC (Engine *, unsigned int port);
+ virtual ~ControlOSC();
+
+ std::string get_server_url();
+ int get_server_port () { return _port; }
+
+ bool is_ok() { return _ok; }
+
+
+ private:
+
+ struct CommandInfo
+ {
+ CommandInfo (ControlOSC * os, int n, Event::type_t t)
+ : osc(os), instance(n), type(t) {}
+
+ ControlOSC * osc;
+ int instance;
+ Event::type_t type;
+ };
+
+
+ void on_loop_added(int instance);
+ void on_loop_removed();
+
+
+ static int _quit_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);
+ static int _updown_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);
+ static int _set_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);
+ static int _get_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);
+ static int _dummy_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);
+
+
+ int quit_handler(const char *path, const char *types, lo_arg **argv, int argc,void *data);
+
+ int updown_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, CommandInfo * info);
+ int set_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, CommandInfo * info);
+ int get_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, CommandInfo * info);
+
+ Event::command_t to_command_t (std::string cmd);
+ std::string to_command_str (Event::command_t cmd);
+
+ Event::control_t to_control_t (std::string cmd);
+ std::string to_control_str (Event::control_t cmd);
+
+ Engine * _engine;
+
+ lo_server_thread _sthread;
+ int _port;
+ bool _ok;
+
+
+ std::map<std::string, lo_address> _retaddr_map;
+};
+
+}; // sooperlooper namespace
+
+#endif
View
420 src/engine.cpp
@@ -0,0 +1,420 @@
+/*
+** Copyright (C) 2004 Jesse Chappell <jesse@essej.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+#include <iostream>
+
+#include <jack/jack.h>
+
+#include "engine.hpp"
+#include "looper.hpp"
+#include "control_osc.hpp"
+
+using namespace SooperLooper;
+using namespace std;
+using namespace PBD;
+
+#define MAX_EVENTS 1024
+
+
+Engine::Engine (string jack_name)
+ : _jack_name(jack_name)
+{
+ _ok = false;
+ _jack = 0;
+ _osc = 0;
+}
+
+bool Engine::initialize(int port)
+{
+ if (connect_to_jack ()) {
+ cerr << "cannot connect to jack" << endl;
+ return false;
+ }
+
+ _samplerate = jack_get_sample_rate (_jack);
+
+ _event_generator = new EventGenerator(_samplerate);
+ _event_queue = new RingBuffer<Event> (MAX_EVENTS);
+
+ _osc = new ControlOSC(this, port);
+
+ if (!_osc->is_ok()) {
+ return false;
+ }
+
+
+ if (jack_set_process_callback (_jack, _process_callback, this) != 0) {
+ return false;
+ }
+
+
+ _ok = true;
+
+ return true;
+}
+
+bool Engine::activate()
+{
+ if (_jack) {
+ if (jack_activate (_jack)) {
+ cerr << "cannot activate JACK" << endl;
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool Engine::deactivate()
+{
+ if (_jack) {
+ if (jack_deactivate (_jack)) {
+ cerr << "cannot deactivate JACK" << endl;
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void
+Engine::cleanup()
+{
+ if (_ok) {
+ jack_client_close (_jack);
+
+ delete _osc;
+
+ delete _event_queue;
+ _event_queue = 0;
+
+ delete _event_generator;
+ _event_generator = 0;
+
+ _ok = false;
+ }
+}
+
+Engine::~Engine ()
+{
+ cleanup ();
+}
+
+void Engine::quit()
+{
+
+ _ok = false;
+}
+
+
+bool
+Engine::add_loop (unsigned int chans)
+{
+ int n;
+
+ {
+ LockMonitor lm (_instance_lock, __LINE__, __FILE__);
+
+ Looper * instance;
+
+ instance = new Looper (_jack, (unsigned int) _instances.size(), chans);
+ n = _instances.size();
+
+ if (!(*instance)()) {
+ cerr << "can't create a new loop!\n";
+ delete instance;
+ return false;
+ }
+
+ _instances.push_back (instance);
+ }
+
+ LoopAdded (n); // emit
+
+ return true;
+}
+
+
+bool
+Engine::remove_loop (unsigned int index)
+{
+ LockMonitor lm (_instance_lock, __LINE__, __FILE__);
+
+ if (index < _instances.size()) {
+
+ Instances::iterator iter = _instances.begin();
+ iter += index;
+
+ Looper * loop = (*iter);
+ _instances.erase (iter);
+
+ delete loop;
+ LoopRemoved(); // emit
+ }
+}
+
+
+std::string
+Engine::get_osc_url ()
+{
+ if (_osc && _osc->is_ok()) {
+ return _osc->get_server_url();
+ }
+
+ return "";
+}
+
+int
+Engine::get_osc_port ()
+{
+ if (_osc && _osc->is_ok()) {
+ return _osc->get_server_port();
+ }
+
+ return 0;
+}
+
+
+static void
+our_jack_error(const char * err)
+{
+
+}
+
+int
+Engine::connect_to_jack ()
+{
+ char namebuf[100];
+
+ jack_set_error_function (our_jack_error);
+
+ _jack = 0;
+
+ /* try to become a client of the JACK server */
+ if (_jack_name.empty()) {
+ // find a name predictably
+ for (int i=1; i < 10; i++) {
+ snprintf(namebuf, sizeof(namebuf)-1, "sooperlooper_%d", i);
+ if ((_jack = jack_client_new (namebuf)) != 0) {
+ _jack_name = namebuf;
+ break;
+ }
+ }
+ }
+ else {
+ // try the passed name, or base a predictable name from it
+ if ((_jack = jack_client_new (_jack_name.c_str())) == 0) {
+ for (int i=1; i < 10; i++) {
+ snprintf(namebuf, sizeof(namebuf)-1, "%s_%d", _jack_name.c_str(), i);
+ if ((_jack = jack_client_new (namebuf)) != 0) {
+ _jack_name = namebuf;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!_jack) {
+ return -1;
+ }
+
+ jack_set_xrun_callback (_jack, _xrun_callback, this);
+
+ return 0;
+}
+
+int
+Engine::_xrun_callback (void* arg)
+{
+ cerr << "got xrun" << endl;
+}
+
+
+int
+Engine::_process_callback (jack_nframes_t nframes, void* arg)
+{
+ return static_cast<Engine*> (arg)->process_callback (nframes);
+}
+
+int
+Engine::process_callback (jack_nframes_t nframes)
+{
+ TentativeLockMonitor lm (_instance_lock, __LINE__, __FILE__);
+
+ Event * evt;
+ RingBuffer<Event>::rw_vector vec;
+
+
+ // get available events
</