-Add: Curses UI. Beware of coding style...
git-svn-id: http://svn.fuzzle.org/mloop/mloop/trunk@8 ba049829-c6ef-42ef-81ac-908dd8d2e907remotes/git-svn@10
parent
4a7ee4a61a
commit
4ba9b7cc26
|
@ -1,6 +1,5 @@
|
|||
/* $Id$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <jack/jack.h>
|
||||
|
@ -108,7 +107,7 @@ int Jack::ProcessCallback(jack_nframes_t nframes)
|
|||
m_buffer->Write((uint8_t *)&ev.size, sizeof ev.size);
|
||||
m_buffer->Write((uint8_t *)ev.buffer, ev.size);
|
||||
} else {
|
||||
printf("Buffer full, dropping input!\n");
|
||||
fprintf(stderr, "Buffer full, dropping input!\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,6 +125,7 @@ int Jack::ProcessCallback(jack_nframes_t nframes)
|
|||
|
||||
if (m_recording) {
|
||||
m_recording_time += nframes;
|
||||
m_loops[m_recording_loop].SetLength(m_recording_time);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -136,9 +136,11 @@ void Jack::ToggleRecording(int loop)
|
|||
if (m_recording) {
|
||||
m_recording = false;
|
||||
m_loops[m_recording_loop].SetLength(m_recording_time);
|
||||
m_loops[m_recording_loop].SetState(LS_IDLE);
|
||||
m_loops[m_recording_loop].EndFromNoteCache(m_notecache);
|
||||
} else {
|
||||
m_recording_loop = loop;
|
||||
m_loops[m_recording_loop].SetState(LS_RECORDING);
|
||||
m_loops[m_recording_loop].StartFromNoteCache(m_notecache);
|
||||
m_recording_time = 0;
|
||||
m_recording = true;
|
||||
|
|
15
src/jack.h
15
src/jack.h
|
@ -58,6 +58,21 @@ public:
|
|||
{
|
||||
return m_recording;
|
||||
}
|
||||
|
||||
float LoopLength(int loop)
|
||||
{
|
||||
return (float)m_loops[loop].Length() / m_sample_rate;
|
||||
}
|
||||
|
||||
float LoopPosition(int loop)
|
||||
{
|
||||
return (float)m_loops[loop].Position() / m_sample_rate;
|
||||
}
|
||||
|
||||
LoopState GetLoopState(int loop)
|
||||
{
|
||||
return m_loops[loop].State();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* JACK_H */
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* $Id$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "loop.h"
|
||||
|
||||
Loop::Loop()
|
||||
|
@ -16,11 +15,9 @@ Loop::~Loop()
|
|||
|
||||
void Loop::PlayFrame(void *port_buffer, jack_nframes_t frame)
|
||||
{
|
||||
if (m_state == LS_IDLE) return;
|
||||
if (m_state == LS_IDLE || m_state == LS_RECORDING) return;
|
||||
|
||||
if (m_state == LS_STOPPING) {
|
||||
printf("Stopping, so send all notes off!\n");
|
||||
|
||||
uint8_t buffer[3];
|
||||
buffer[1] = 0x78;
|
||||
buffer[2] = 0;
|
||||
|
@ -49,7 +46,6 @@ void Loop::PlayFrame(void *port_buffer, jack_nframes_t frame)
|
|||
if (m_state == LS_PLAY_ONCE) {
|
||||
m_state = LS_IDLE;
|
||||
}
|
||||
printf("Completed %u frames\n", m_position);
|
||||
m_position = 0;
|
||||
m_iterator = m_events.begin();
|
||||
}
|
||||
|
@ -65,7 +61,7 @@ void Loop::AddEvent(jack_nframes_t position, jack_midi_event_t *event)
|
|||
|
||||
void Loop::SetLength(jack_nframes_t length)
|
||||
{
|
||||
if (m_state != LS_IDLE) return;
|
||||
if (m_state != LS_RECORDING) return;
|
||||
|
||||
m_length = length;
|
||||
}
|
||||
|
|
21
src/loop.h
21
src/loop.h
|
@ -14,6 +14,7 @@ enum LoopState {
|
|||
LS_PLAY_LOOP,
|
||||
LS_PLAY_ONCE,
|
||||
LS_STOPPING,
|
||||
LS_RECORDING,
|
||||
};
|
||||
|
||||
typedef std::pair<jack_midi_event_t, jack_nframes_t> Event;
|
||||
|
@ -35,6 +36,11 @@ public:
|
|||
void PlayFrame(void *port_buffer, jack_nframes_t frame);
|
||||
void AddEvent(jack_nframes_t position, jack_midi_event_t *event);
|
||||
|
||||
void SetState(LoopState state)
|
||||
{
|
||||
m_state = state;
|
||||
}
|
||||
|
||||
void SetLength(jack_nframes_t length);
|
||||
void Start(bool loop);
|
||||
void Stop();
|
||||
|
@ -42,6 +48,21 @@ public:
|
|||
|
||||
void StartFromNoteCache(NoteCache &cache);
|
||||
void EndFromNoteCache(NoteCache &cache);
|
||||
|
||||
LoopState State() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
jack_nframes_t Length() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
jack_nframes_t Position() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* LOOP_H */
|
||||
|
|
99
src/ui.cpp
99
src/ui.cpp
|
@ -3,9 +3,11 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <curses.h>
|
||||
#include <sys/select.h>
|
||||
#include <termios.h>
|
||||
#include "jack.h"
|
||||
#include "loop.h"
|
||||
#include "ui.h"
|
||||
|
||||
struct termios orig_termios;
|
||||
|
@ -21,12 +23,14 @@ void set_conio_terminal_mode()
|
|||
|
||||
/* take two copies - one for now, one for later */
|
||||
tcgetattr(0, &orig_termios);
|
||||
#if 0
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
int kbhit()
|
||||
|
@ -37,6 +41,7 @@ int kbhit()
|
|||
return select(1, &fds, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
/*
|
||||
int getch()
|
||||
{
|
||||
int r;
|
||||
|
@ -47,27 +52,95 @@ int getch()
|
|||
return c;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
int bpm = 120;
|
||||
int color_map[4];
|
||||
char status[1024];
|
||||
|
||||
bool UI::Run(Jack &j)
|
||||
{
|
||||
char buf[1024];
|
||||
static bool first = true;
|
||||
if (first) {
|
||||
set_conio_terminal_mode();
|
||||
first = false;
|
||||
m_loop = 0;
|
||||
|
||||
initscr();
|
||||
noecho();
|
||||
nonl();
|
||||
intrflush(stdscr, false);
|
||||
keypad(stdscr, true);
|
||||
nodelay(stdscr, true);
|
||||
raw();
|
||||
|
||||
start_color();
|
||||
init_pair(1, COLOR_WHITE, COLOR_BLUE);
|
||||
init_pair(2, COLOR_BLACK, COLOR_CYAN);
|
||||
init_pair(3, COLOR_YELLOW, COLOR_RED);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
color_map[i] = COLOR_PAIR(i);
|
||||
}
|
||||
|
||||
snprintf(status, sizeof status, "...");
|
||||
}
|
||||
|
||||
if (!kbhit()) return false;
|
||||
snprintf(buf, sizeof buf, " mloop -- %d bpm", bpm);
|
||||
bkgdset(color_map[1]);
|
||||
attrset(color_map[1]);
|
||||
mvaddstr(0, 0, buf);
|
||||
clrtoeol();
|
||||
|
||||
char c = getch();
|
||||
mvaddstr(11, 0, status);
|
||||
clrtoeol();
|
||||
|
||||
for (int i = 0; i < NUM_LOOPS; i++) {
|
||||
bkgdset(color_map[0]);
|
||||
attrset(color_map[0]);
|
||||
|
||||
snprintf(buf, sizeof buf, " [ ] %2d: Position: %0.2f beats (%0.2fs) Length: %0.2f beats (%0.2fs)", i, bpm * j.LoopPosition(i) / 60.0, j.LoopPosition(i), bpm * j.LoopLength(i) / 60.0, j.LoopLength(i));
|
||||
mvaddstr(i + 1, 0, buf);
|
||||
clrtoeol();
|
||||
|
||||
const char *c; int k = 3;
|
||||
switch (j.GetLoopState(i)) {
|
||||
case LS_IDLE: c = " "; k = 0; break;
|
||||
case LS_PLAY_ONCE: c = ">"; break;
|
||||
case LS_PLAY_LOOP: c = "»"; break;
|
||||
case LS_STOPPING: c = "·"; break;
|
||||
case LS_RECORDING: c = "R"; break;
|
||||
}
|
||||
|
||||
bkgdset(color_map[m_loop == i ? 2 : k]);
|
||||
attrset(color_map[m_loop == i ? 2 : k]);
|
||||
|
||||
mvaddstr(i + 1, 2, c);
|
||||
}
|
||||
|
||||
if (!kbhit()) {
|
||||
refresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
int c = getch();
|
||||
|
||||
switch (c) {
|
||||
case 3:
|
||||
case 'q': return true;
|
||||
case 'q': {
|
||||
endwin();
|
||||
reset_terminal_mode();
|
||||
return true;
|
||||
}
|
||||
|
||||
case 'r':
|
||||
j.ToggleRecording(m_loop);
|
||||
printf("%s recording loop\n", j.Recording() ? "Started" : "Finished");
|
||||
if (j.Recording()) {
|
||||
snprintf(status, sizeof status, "Start recording loop %d", m_loop);
|
||||
} else {
|
||||
snprintf(status, sizeof status, "Finished recording loop");
|
||||
}
|
||||
break;
|
||||
|
||||
case '0':
|
||||
|
@ -81,24 +154,34 @@ bool UI::Run(Jack &j)
|
|||
case '8':
|
||||
case '9':
|
||||
m_loop = (c - '0');
|
||||
printf("Selected loop %d\n", m_loop);
|
||||
snprintf(status, sizeof status, "Selected loop %d", m_loop);
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
case 'x':
|
||||
printf("Starting loop %d (%s)\n", m_loop, c == 'x' ? "loop" : "once");
|
||||
snprintf(status, sizeof status, "Starting loop %d (%s)", m_loop, c == 'x' ? "loop" : "once");
|
||||
j.StartLoop(m_loop, c == 'x');
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf("Stopping loop %d\n", m_loop);
|
||||
snprintf(status, sizeof status, "Stopping loop %d", m_loop);
|
||||
j.StopLoop(m_loop);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
printf("Erasing loop %d\n", m_loop);
|
||||
snprintf(status, sizeof status, "Erasing loop %d", m_loop);
|
||||
j.EraseLoop(m_loop);
|
||||
break;
|
||||
|
||||
case KEY_UP:
|
||||
m_loop--;
|
||||
if (m_loop == -1) m_loop = NUM_LOOPS - 1;
|
||||
break;
|
||||
|
||||
case KEY_DOWN:
|
||||
m_loop++;
|
||||
if (m_loop == NUM_LOOPS) m_loop = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
def configure(conf):
|
||||
conf.check_cfg(package='jack', uselib_store='JACK', args='--cflags --libs', atleast_version='1.9.2')
|
||||
conf.env['LIB_NCURSES'] = ['ncurses']
|
||||
|
||||
def build(bld):
|
||||
bld.new_task_gen(
|
||||
features = 'cxx cprogram',
|
||||
source = 'jack.cpp loop.cpp mloop.cpp ui.cpp',
|
||||
target = 'mloop',
|
||||
uselib = 'JACK')
|
||||
uselib = 'JACK NCURSES')
|
||||
|
|
Loading…
Reference in New Issue