diff --git a/modules/fluxus-midi/src/FluxusMIDI.cpp b/modules/fluxus-midi/src/FluxusMIDI.cpp
index efe6af9..c9654d9 100644
--- a/modules/fluxus-midi/src/FluxusMIDI.cpp
+++ b/modules/fluxus-midi/src/FluxusMIDI.cpp
@@ -306,6 +306,74 @@ Scheme_Object *midi_note(int argc, Scheme_Object **argv)
 }
 
 // StartFunctionDoc-en
+// midi-program channel-number
+// Returns: program-value-number
+// Description:
+// Returns the program value.
+// Example:
+// (midi-program 0)
+// EndFunctionDoc
+
+Scheme_Object *midi_program(int argc, Scheme_Object **argv)
+{
+	Scheme_Object *ret = NULL;
+	MZ_GC_DECL_REG(2);
+	MZ_GC_VAR_IN_REG(0, argv);
+	MZ_GC_VAR_IN_REG(1, ret);
+	MZ_GC_REG();
+
+	if (!SCHEME_NUMBERP(argv[0]))
+		scheme_wrong_type("midi-program", "number", 0, argc, argv);
+
+	int channel = (int)scheme_real_to_double(argv[0]);
+	
+	if (midilistener != NULL)
+	{
+		int val = midilistener->get_program(channel);
+		ret = scheme_make_integer(val);
+	}
+	else
+	{
+		ret = scheme_void;
+	}
+
+	MZ_GC_UNREG();
+	return ret;
+} // midi_program(..)
+
+// midi-cc-event
+// Returns: #(channel controller value) or #f
+// Description:
+// Returns the next event from the MIDI note event queue or #f if the queue is empty.
+// Example:
+// (midi-cc-event)
+// EndFunctionDoc
+Scheme_Object *midi_cc_event(int argc, Scheme_Object **argv)
+{
+	Scheme_Object *ret = NULL;
+	MZ_GC_DECL_REG(2);
+	MZ_GC_VAR_IN_REG(2, ret);
+	MZ_GC_REG();
+
+	ret = scheme_false;
+	if (midilistener != NULL)
+	{
+		MIDIEvent *evt = midilistener->get_cc_event();
+		if (evt)
+		{
+			ret = scheme_make_vector(3, scheme_void);
+			SCHEME_VEC_ELS(ret)[0] = scheme_make_integer(evt->channel);
+			SCHEME_VEC_ELS(ret)[1] = scheme_make_integer(evt->controller);
+			SCHEME_VEC_ELS(ret)[2] = scheme_make_integer(evt->value);
+		}
+	}
+
+	MZ_GC_UNREG();
+	return ret;
+
+} // midi_cc_event(..)
+
+// StartFunctionDoc-en
 // midi-peek
 // Returns: msg-string
 // Description:
@@ -364,6 +432,10 @@ Scheme_Object *scheme_reload(Scheme_Env *env)
 			scheme_make_prim_w_arity(midi_note, "midi-note", 0, 0), menv);
 	scheme_add_global("midi-peek",
 			scheme_make_prim_w_arity(midi_peek, "midi-peek", 0, 0), menv);
+	scheme_add_global("midi-program",
+			scheme_make_prim_w_arity(midi_program, "midi-program", 1, 1), menv);
+	scheme_add_global("midi-cc-event",
+			scheme_make_prim_w_arity(midi_cc_event, "midi-cc-event", 0, 0), menv);
 
 	scheme_finish_primitive_module(menv);
 	MZ_GC_UNREG();
diff --git a/modules/fluxus-midi/src/MIDIListener.cpp b/modules/fluxus-midi/src/MIDIListener.cpp
index ee759d1..7117b23 100644
--- a/modules/fluxus-midi/src/MIDIListener.cpp
+++ b/modules/fluxus-midi/src/MIDIListener.cpp
@@ -24,6 +24,8 @@ using namespace std;
 
 /** maximum number of midi notes stored */
 static const unsigned MAX_MIDI_NOTE_COUNT = 256;
+/** maximum number of midi events stored.. there could be *a lot* of events, so this size is intensionally left small. **/
+static const unsigned MAX_MIDI_EVENT_COUNT = 16;
 
 MIDINote::MIDINote(int _on_off, int _channel, int _note, int _velocity) :
 	on_off(_on_off),
@@ -33,6 +35,13 @@ MIDINote::MIDINote(int _on_off, int _channel, int _note, int _velocity) :
 {
 }
 
+MIDIEvent::MIDIEvent(int _channel, int _controller, int _value) :
+	channel(_channel),
+	controller(_controller),
+	value(_value)
+{
+}
+
 void midi_callback(double deltatime, vector<unsigned char> *message,
 		void *user_data)
 {
@@ -52,6 +61,10 @@ MIDIListener::MIDIListener(int port /*= -1*/) :
 	cntrl_values = new unsigned char[MAX_CNTRL];
 	fill(cntrl_values, cntrl_values + MAX_CNTRL, 0);
 
+	/* likewise for the per channel "program" values */
+	pgm_values = new unsigned char[MAX_CHAN];
+	fill(pgm_values, pgm_values + MAX_CHAN, 0); 
+
 	pthread_mutex_init(&mutex, NULL);
 }
 
@@ -193,6 +206,26 @@ int MIDIListener::get_cc(int channel, int cntrl_number)
 }
 
 /**
+ * Returns program value.
+ * \param channel MIDI channel
+ * \retval int program value
+ **/
+int MIDIListener::get_program(int channel)
+{
+	if (midiin == NULL)
+	{
+		init_midi();
+		if (midiin == NULL)
+			return 0;
+	}
+
+	pthread_mutex_lock(&mutex);
+	int v = pgm_values[ channel ];
+	pthread_mutex_unlock(&mutex);
+	return v;
+}
+
+/**
  * Returns normalised controller values.
  * \param channel MIDI channel
  * \param cntrl_number controller number
@@ -257,6 +290,46 @@ MIDINote *MIDIListener::get_note(void)
 }
 
 /**
+ * Returns next MIDI controller event from event queue.
+ * \retval MIDIEvent* pointer to MIDI Event or NULL if the queue is empty
+ **/
+MIDIEvent *MIDIListener::get_cc_event(void)
+{
+	static MIDIEvent evt;
+
+	pthread_mutex_lock(&mutex);
+	if (midi_events.empty())
+	{
+		pthread_mutex_unlock(&mutex);
+		return NULL;
+	}
+
+	MIDIEvent *n = midi_events.front();
+	midi_events.pop_front();
+	pthread_mutex_unlock(&mutex);
+
+	evt.channel = n->channel;
+	evt.value = n->value;
+	evt.controller = n->controller;
+	delete n;
+	return &evt;
+}
+
+/**
+ * Adds a new event to the event queue.
+ **/
+void MIDIListener::add_event(int channel, int controller, int value)
+{
+	MIDIEvent *n = new MIDIEvent(channel,controller,value);
+	midi_events.push_back(n);
+	while (midi_events.size() > MAX_MIDI_EVENT_COUNT)
+	{
+		delete midi_events.front();
+		midi_events.pop_front();
+	}
+}
+
+/**
  * Adds a new note to the event queue.
  **/
 void MIDIListener::add_note(int on_off, int ch, int note, int velocity)
@@ -281,6 +354,16 @@ void MIDIListener::callback(double deltatime, vector<unsigned char> *message)
 
 	switch (status)
 	{
+		case MIDIListener::MIDI_PROGRAM_CHANGE:
+			if (count == 2)
+			{
+				int program_number = (*message)[1];
+				pthread_mutex_lock(&mutex);
+				pgm_values[ch] = program_number;
+				pthread_mutex_unlock(&mutex);
+			}
+			break;
+			
 		case MIDIListener::MIDI_CONTROLLER:
 			if (count == 3)
 			{
@@ -290,6 +373,7 @@ void MIDIListener::callback(double deltatime, vector<unsigned char> *message)
 				int value = (*message)[2]; /* controller value */
 				pthread_mutex_lock(&mutex);
 				cntrl_values[i] = value;
+				add_event(ch, cntrl_number, value);
 				pthread_mutex_unlock(&mutex);
 			}
 			break;
diff --git a/modules/fluxus-midi/src/MIDIListener.h b/modules/fluxus-midi/src/MIDIListener.h
index 145dbc9..dfe65f2 100644
--- a/modules/fluxus-midi/src/MIDIListener.h
+++ b/modules/fluxus-midi/src/MIDIListener.h
@@ -26,7 +26,8 @@
 
 using namespace std;
 
-#define MAX_CNTRL (16*128)
+#define MAX_CHAN   16
+#define MAX_CNTRL (MAX_CHAN*128)
 
 class MIDINote
 {
@@ -40,6 +41,16 @@ class MIDINote
 			int velocity; /**< velocity of MIDI note */
 };
 
+class MIDIEvent
+{
+	public:
+			MIDIEvent() { channel = controller = value; }
+			MIDIEvent(int channel, int controller, int value);
+			int channel;	/**< MIDI channel (>=0) **/
+			int controller;	/*<< MIDI controller number **/
+			int value; /**< the actual controller value **/
+};
+
 class MIDIListener
 {
 	public:
@@ -53,10 +64,12 @@ class MIDIListener
 
 			int get_cc(int channel, int cntrl_number);
 			float get_ccn(int channel, int cntrl_number);
+			int get_program(int channel);
 
 			string get_last_event(void);
 
-			MIDINote *get_note(void);
+			MIDINote *get_note(void);			
+			MIDIEvent *get_cc_event(void);
 
 			enum {
 				MIDI_NOTE_OFF = 0x08,
@@ -68,6 +81,7 @@ class MIDIListener
 	private:
 			void init_midi(void);
 			void add_note(int on_off, int ch, int note, int velocity);
+			void add_event(int channel, int controller, int value);
 
 			pthread_mutex_t mutex;
 
@@ -78,8 +92,12 @@ class MIDIListener
 
 			/** array holding the current state of all, 16*128 controllers */
 			unsigned char *cntrl_values;
-
+			
+			/** array holding program number of 16 channels **/
+			unsigned char *pgm_values;
+			
 			deque<MIDINote *> midi_notes;
+			deque<MIDIEvent *> midi_events;
 };
 
 #endif