-Change: Split off UI.
git-svn-id: http://svn.fuzzle.org/mloop/mloop/trunk@7 ba049829-c6ef-42ef-81ac-908dd8d2e907remotes/git-svn@10
parent
f330095902
commit
4a7ee4a61a
177
src/jack.cpp
177
src/jack.cpp
|
@ -3,9 +3,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
#include <jack/midiport.h>
|
#include <jack/midiport.h>
|
||||||
#include "jack.h"
|
#include "jack.h"
|
||||||
|
@ -41,6 +38,8 @@ bool Jack::Connect()
|
||||||
|
|
||||||
m_connected = true;
|
m_connected = true;
|
||||||
|
|
||||||
|
m_sample_rate = jack_get_sample_rate(m_client);
|
||||||
|
|
||||||
jack_on_shutdown(m_client, &ShutdownCallbackHandler, this);
|
jack_on_shutdown(m_client, &ShutdownCallbackHandler, this);
|
||||||
jack_set_process_callback(m_client, &ProcessCallbackHandler, this);
|
jack_set_process_callback(m_client, &ProcessCallbackHandler, this);
|
||||||
|
|
||||||
|
@ -132,129 +131,63 @@ int Jack::ProcessCallback(jack_nframes_t nframes)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct termios orig_termios;
|
void Jack::ToggleRecording(int loop)
|
||||||
|
|
||||||
void reset_terminal_mode()
|
|
||||||
{
|
{
|
||||||
tcsetattr(0, TCSANOW, &orig_termios);
|
if (m_recording) {
|
||||||
}
|
m_recording = false;
|
||||||
|
m_loops[m_recording_loop].SetLength(m_recording_time);
|
||||||
void set_conio_terminal_mode()
|
m_loops[m_recording_loop].EndFromNoteCache(m_notecache);
|
||||||
{
|
|
||||||
struct termios new_termios;
|
|
||||||
|
|
||||||
/* take two copies - one for now, one for later */
|
|
||||||
tcgetattr(0, &orig_termios);
|
|
||||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
|
||||||
|
|
||||||
/* register cleanup handler, and set the new terminal mode */
|
|
||||||
atexit(reset_terminal_mode);
|
|
||||||
cfmakeraw(&new_termios);
|
|
||||||
tcsetattr(0, TCSANOW, &new_termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kbhit()
|
|
||||||
{
|
|
||||||
struct timeval tv = { 0L, 0L };
|
|
||||||
fd_set fds;
|
|
||||||
FD_SET(0, &fds);
|
|
||||||
return select(1, &fds, NULL, NULL, &tv);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getch()
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
unsigned char c;
|
|
||||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
|
||||||
return r;
|
|
||||||
} else {
|
} else {
|
||||||
return c;
|
m_recording_loop = loop;
|
||||||
|
m_loops[m_recording_loop].StartFromNoteCache(m_notecache);
|
||||||
|
m_recording_time = 0;
|
||||||
|
m_recording = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jack::Run()
|
void Jack::StartLoop(int loop, bool repeat)
|
||||||
{
|
{
|
||||||
set_conio_terminal_mode();
|
m_loops[loop].Start(repeat);
|
||||||
|
|
||||||
jack_nframes_t recording_time;
|
|
||||||
jack_midi_event_t ev;
|
|
||||||
ev.time = UINT_MAX;
|
|
||||||
|
|
||||||
m_recording = false;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
usleep(10000);
|
|
||||||
if (ev.time == UINT_MAX) {
|
|
||||||
if (m_buffer->Size() >= sizeof recording_time + sizeof ev.time + sizeof ev.size) {
|
|
||||||
m_buffer->Read((uint8_t *)&recording_time, sizeof recording_time);
|
|
||||||
m_buffer->Read((uint8_t *)&ev.time, sizeof ev.time);
|
|
||||||
m_buffer->Read((uint8_t *)&ev.size, sizeof ev.size);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (m_buffer->Size() >= ev.size) {
|
|
||||||
ev.buffer = (jack_midi_data_t *)malloc(ev.size);
|
|
||||||
m_buffer->Read((uint8_t *)ev.buffer, ev.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_recording) {
|
|
||||||
printf("Recording event for loop %d\n", m_recording_loop);
|
|
||||||
m_loops[m_recording_loop].AddEvent(recording_time, &ev);
|
|
||||||
}
|
|
||||||
ev.time = UINT_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kbhit()) {
|
|
||||||
char c = getch();
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case 3:
|
|
||||||
case 'q': return;
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
if (m_recording) {
|
|
||||||
m_recording = false;
|
|
||||||
m_loops[m_recording_loop].SetLength(m_recording_time);
|
|
||||||
m_loops[m_recording_loop].EndFromNoteCache(m_notecache);
|
|
||||||
printf("Finished recording loop %d\n", m_recording_loop);
|
|
||||||
} else {
|
|
||||||
m_loops[m_recording_loop].StartFromNoteCache(m_notecache);
|
|
||||||
m_recording_time = 0;
|
|
||||||
m_recording = true;
|
|
||||||
printf("Started recording loop %d\n", m_recording_loop);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
if (!m_recording) {
|
|
||||||
m_recording_loop = c - '1';
|
|
||||||
printf("Selected recording loop %d\n", m_recording_loop);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'z':
|
|
||||||
case 'x':
|
|
||||||
printf("Starting loop %d (%s)\n", m_recording_loop, c == 'x' ? "loop" : "once");
|
|
||||||
m_loops[m_recording_loop].Start(c == 'x');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'c':
|
|
||||||
printf("Stopping loop %d\n", m_recording_loop);
|
|
||||||
m_loops[m_recording_loop].Stop();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'e':
|
|
||||||
printf("Erasing loop %d\n", m_recording_loop);
|
|
||||||
m_loops[m_recording_loop].Empty();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Jack::StopLoop(int loop)
|
||||||
|
{
|
||||||
|
m_loops[loop].Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Jack::EraseLoop(int loop)
|
||||||
|
{
|
||||||
|
m_loops[loop].Empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Jack::Run()
|
||||||
|
{
|
||||||
|
static jack_nframes_t recording_time;
|
||||||
|
static jack_midi_event_t ev;
|
||||||
|
static bool first = true;
|
||||||
|
if (first) {
|
||||||
|
ev.time = UINT_MAX;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev.time == UINT_MAX) {
|
||||||
|
if (m_buffer->Size() >= sizeof recording_time + sizeof ev.time + sizeof ev.size) {
|
||||||
|
m_buffer->Read((uint8_t *)&recording_time, sizeof recording_time);
|
||||||
|
m_buffer->Read((uint8_t *)&ev.time, sizeof ev.time);
|
||||||
|
m_buffer->Read((uint8_t *)&ev.size, sizeof ev.size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_buffer->Size() >= ev.size) {
|
||||||
|
ev.buffer = (jack_midi_data_t *)malloc(ev.size);
|
||||||
|
m_buffer->Read((uint8_t *)ev.buffer, ev.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_recording) {
|
||||||
|
m_loops[m_recording_loop].AddEvent(recording_time, &ev);
|
||||||
|
}
|
||||||
|
ev.time = UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
16
src/jack.h
16
src/jack.h
|
@ -8,7 +8,7 @@
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "notecache.h"
|
#include "notecache.h"
|
||||||
|
|
||||||
#define NUM_LOOPS 9
|
#define NUM_LOOPS 10
|
||||||
|
|
||||||
class Jack {
|
class Jack {
|
||||||
private:
|
private:
|
||||||
|
@ -18,6 +18,8 @@ private:
|
||||||
jack_port_t *m_output;
|
jack_port_t *m_output;
|
||||||
jack_port_t *m_control;
|
jack_port_t *m_control;
|
||||||
|
|
||||||
|
jack_nframes_t m_sample_rate;
|
||||||
|
|
||||||
Loop m_loops[NUM_LOOPS];
|
Loop m_loops[NUM_LOOPS];
|
||||||
RingBuffer *m_buffer;
|
RingBuffer *m_buffer;
|
||||||
|
|
||||||
|
@ -45,7 +47,17 @@ public:
|
||||||
|
|
||||||
bool Connect();
|
bool Connect();
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
void Run();
|
bool Run();
|
||||||
|
|
||||||
|
void ToggleRecording(int loop);
|
||||||
|
void StartLoop(int loop, bool repeat);
|
||||||
|
void StopLoop(int loop);
|
||||||
|
void EraseLoop(int loop);
|
||||||
|
|
||||||
|
bool Recording() const
|
||||||
|
{
|
||||||
|
return m_recording;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* JACK_H */
|
#endif /* JACK_H */
|
||||||
|
|
|
@ -1,15 +1,23 @@
|
||||||
/* $Id$ */
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
#include "jack.h"
|
#include "jack.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
Jack *j = new Jack();
|
Jack j;
|
||||||
|
UI u;
|
||||||
|
|
||||||
j->Connect();
|
j.Connect();
|
||||||
j->Run();
|
|
||||||
|
|
||||||
delete j;
|
while (true) {
|
||||||
|
if (j.Run()) break;
|
||||||
|
if (u.Run(j)) break;
|
||||||
|
usleep(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
j.Disconnect();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include "jack.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
struct termios orig_termios;
|
||||||
|
|
||||||
|
void reset_terminal_mode()
|
||||||
|
{
|
||||||
|
tcsetattr(0, TCSANOW, &orig_termios);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_conio_terminal_mode()
|
||||||
|
{
|
||||||
|
struct termios new_termios;
|
||||||
|
|
||||||
|
/* take two copies - one for now, one for later */
|
||||||
|
tcgetattr(0, &orig_termios);
|
||||||
|
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
||||||
|
|
||||||
|
/* register cleanup handler, and set the new terminal mode */
|
||||||
|
atexit(reset_terminal_mode);
|
||||||
|
cfmakeraw(&new_termios);
|
||||||
|
tcsetattr(0, TCSANOW, &new_termios);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kbhit()
|
||||||
|
{
|
||||||
|
struct timeval tv = { 0L, 0L };
|
||||||
|
fd_set fds;
|
||||||
|
FD_SET(0, &fds);
|
||||||
|
return select(1, &fds, NULL, NULL, &tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getch()
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
unsigned char c;
|
||||||
|
if ((r = read(0, &c, sizeof(c))) < 0) {
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UI::Run(Jack &j)
|
||||||
|
{
|
||||||
|
static bool first = true;
|
||||||
|
if (first) {
|
||||||
|
set_conio_terminal_mode();
|
||||||
|
first = false;
|
||||||
|
m_loop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kbhit()) return false;
|
||||||
|
|
||||||
|
char c = getch();
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 3:
|
||||||
|
case 'q': return true;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
j.ToggleRecording(m_loop);
|
||||||
|
printf("%s recording loop\n", j.Recording() ? "Started" : "Finished");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
m_loop = (c - '0');
|
||||||
|
printf("Selected loop %d\n", m_loop);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'z':
|
||||||
|
case 'x':
|
||||||
|
printf("Starting loop %d (%s)\n", m_loop, c == 'x' ? "loop" : "once");
|
||||||
|
j.StartLoop(m_loop, c == 'x');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
printf("Stopping loop %d\n", m_loop);
|
||||||
|
j.StopLoop(m_loop);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
printf("Erasing loop %d\n", m_loop);
|
||||||
|
j.EraseLoop(m_loop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#ifndef UI_H
|
||||||
|
#define UI_H
|
||||||
|
|
||||||
|
class UI {
|
||||||
|
private:
|
||||||
|
int m_loop;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool Run(Jack &j);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* UI_H */
|
|
@ -7,6 +7,6 @@ def configure(conf):
|
||||||
def build(bld):
|
def build(bld):
|
||||||
bld.new_task_gen(
|
bld.new_task_gen(
|
||||||
features = 'cxx cprogram',
|
features = 'cxx cprogram',
|
||||||
source = 'jack.cpp loop.cpp mloop.cpp',
|
source = 'jack.cpp loop.cpp mloop.cpp ui.cpp',
|
||||||
target = 'mloop',
|
target = 'mloop',
|
||||||
uselib = 'JACK')
|
uselib = 'JACK')
|
||||||
|
|
Loading…
Reference in New Issue