Skip to content

Commit

Permalink
Merge branch 'chain_manager' of github.com:zynthian/zynthian-ui into …
Browse files Browse the repository at this point in the history
…chain_manager
  • Loading branch information
jofemodo committed Feb 20, 2024
2 parents fe623a7 + 26370a8 commit f2d7b4c
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 40 deletions.
6 changes: 2 additions & 4 deletions zyngine/zynthian_engine_audioplayer.py
Expand Up @@ -94,7 +94,6 @@ def start(self):
def stop(self):
try:
zynaudioplayer.stop()
zynaudioplayer = None
zynsigman.unregister(zynsigman.S_AUDIO_RECORDER, zynthian_audio_recorder.SS_AUDIO_RECORDER_STATE, self.update_rec)
except Exception as e:
logging.error("Failed to close audio player: %s", e)
Expand Down Expand Up @@ -271,7 +270,7 @@ def set_preset(self, processor, preset, preload=False):
self._ctrls = [
['gain', None, gain, 2.0],
['record', None, record, ['stopped', 'recording']],
['loop', None, loop, ['one-shot', 'looping']],
['loop', None, loop, ['one-shot', 'looping', 'play-all', 'toggle']],
['transport', None, transport, ['stopped', 'playing']],
['position', None, 0.0, dur],
['left track', None, default_a, [track_labels, track_values]],
Expand Down Expand Up @@ -391,7 +390,7 @@ def control_cb(self, handle, id, value):
elif id == 3:
ctrl_dict['gain'].set_value(value, False)
elif id == 4:
ctrl_dict['loop'].set_value(int(value) * 64, False)
ctrl_dict['loop'].set_value(int(value), False)
elif id == 5:
ctrl_dict['left track'].set_value(int(value), False)
elif id == 6:
Expand Down Expand Up @@ -558,7 +557,6 @@ def update_rec(self, state):
# Specific functions
# ---------------------------------------------------------------------------


# ---------------------------------------------------------------------------
# API methods
# ---------------------------------------------------------------------------
Expand Down
16 changes: 16 additions & 0 deletions zyngui/zynthian_gui_admin.py
Expand Up @@ -109,6 +109,12 @@ def fill_list(self):
else:
self.list_data.append((self.toggle_midi_sys, 0, "\u2610 MIDI System Messages"))

transpose = lib_zyncore.get_global_transpose()
if transpose > 0:
self.list_data.append((self.global_transpose, transpose, f"[+{transpose}] Global Transpose"))
else:
self.list_data.append((self.global_transpose, transpose, f"[{transpose}] Global Transpose"))

self.list_data.append((None, 0, "> AUDIO"))

if self.state_manager.allow_rbpi_headphones():
Expand Down Expand Up @@ -179,6 +185,7 @@ def select_action(self, i, t='S'):

def set_select_path(self):
self.select_path.set("Admin")
self.set_title("Admin") #TODO: Should not need to set title and select_path!

def execute_commands(self):
self.state_manager.start_busy("admin_commands")
Expand Down Expand Up @@ -351,6 +358,15 @@ def toggle_midi_sys(self):
lib_zyncore.set_midi_filter_system_events(zynthian_gui_config.midi_sys_enabled)
self.fill_list()

def global_transpose(self):
self.enable_param_editor(self, "Global Transpose", {'value_min':-24, 'value_max':24, 'value':lib_zyncore.get_global_transpose()})

def send_controller_value(self, zctrl):
""" Handle param editor"""
if zctrl.symbol == "Global Transpose":
lib_zyncore.set_global_transpose(zctrl.value)
self.fill_list()

def toggle_usbmidi_by_port(self):
if os.environ.get("ZYNTHIAN_USB_MIDI_BY_PORT", "0") == "1":
os.environ["ZYNTHIAN_USB_MIDI_BY_PORT"] = "0"
Expand Down
2 changes: 2 additions & 0 deletions zyngui/zynthian_gui_selector.py
Expand Up @@ -349,6 +349,8 @@ def select_action(self, index, t='S'):
#--------------------------------------------------------------------------

def zynpot_cb(self, i, dval):
if super().zynpot_cb(i, dval):
return
if self.shown and self.zselector and self.zselector.index == i:
self.zselector.zynpot_cb(dval)
if self.index != self.zselector.zctrl.value:
Expand Down
2 changes: 1 addition & 1 deletion zynlibs/zynaudioplayer/audio_player.h
Expand Up @@ -64,7 +64,7 @@ class AUDIO_PLAYER {

uint8_t play_state = STOPPED; // Current playback state (STOPPED|STARTING|PLAYING|STOPPING)
sf_count_t file_read_pos = 0; // Current file read position (frames)
uint8_t loop = 0; // 1 to loop at end of song
uint8_t loop = 0; // 1 to loop at end of song, 2 to play once but ignore note-off
bool looped = false; // True if started playing a loop (not first time)
sf_count_t loop_start = 0; // Start of loop in frames from start of file
sf_count_t loop_start_src = -1; // Start of loop in frames from start after SRC
Expand Down
95 changes: 62 additions & 33 deletions zynlibs/zynaudioplayer/player.cpp
Expand Up @@ -387,7 +387,7 @@ void* file_thread_fn(void * param) {

bool bReverse = (pPlayer->varispeed < 0.0);
if(bReverse) {
if(pPlayer->loop) {
if(pPlayer->loop == 1) {
// Limit read to loop range
if(pPlayer->file_read_pos <= pPlayer->loop_start)
nMaxFrames = 0;
Expand All @@ -398,7 +398,7 @@ void* file_thread_fn(void * param) {
nMaxFrames = pPlayer->file_read_pos - pPlayer->crop_start;
}
} else {
if(pPlayer->loop) {
if(pPlayer->loop == 1) {
// Limit read to loop range
if(pPlayer->file_read_pos >= pPlayer->loop_end)
nMaxFrames = 0;
Expand Down Expand Up @@ -437,7 +437,7 @@ void* file_thread_fn(void * param) {
}
}
else
pPlayer->file_read_pos += nFramesRead = sf_readf_float(pFile, pBufferOut, nMaxFrames);
pPlayer->file_read_pos += (nFramesRead = sf_readf_float(pFile, pBufferOut, nMaxFrames));
} else {
// Populate SRC input buffer before SRC process
if(bReverse) {
Expand All @@ -459,7 +459,7 @@ void* file_thread_fn(void * param) {
}
}
else
pPlayer->file_read_pos += nFramesRead = sf_readf_float(pFile, pBufferIn + nUnusedFrames * pPlayer->sf_info.channels, nMaxFrames);
pPlayer->file_read_pos += (nFramesRead = sf_readf_float(pFile, pBufferIn + nUnusedFrames * pPlayer->sf_info.channels, nMaxFrames));
}

getMutex();
Expand All @@ -473,15 +473,15 @@ void* file_thread_fn(void * param) {
// We need to perform SRC on this block of code
srcData.input_frames = nFramesRead;
int rc = src_process(pSrcState, &srcData);
nUnusedFrames = nFramesRead - srcData.input_frames_used;
nFramesRead = srcData.output_frames_gen;
if(rc) {
DPRINTF("SRC failed with error %d, %lu frames generated\n", nFramesRead, srcData.output_frames_gen);
} else {
DPRINTF("SRC suceeded - %lu frames generated, %lu frames used, %lu frames unused\n", srcData.output_frames_gen, srcData.input_frames_used, nUnusedFrames);
nUnusedFrames = nFramesRead - srcData.input_frames_used;
nFramesRead = srcData.output_frames_gen;
// Shift unused samples to start of buffer
memcpy(pBufferIn, pBufferIn + srcData.input_frames_used * sizeof(float) * pPlayer->sf_info.channels, nUnusedFrames * sizeof(float) * pPlayer->sf_info.channels);
}
// Shift unused samples to start of buffer
memcpy(pBufferIn, pBufferIn + srcData.input_frames_used * sizeof(float) * pPlayer->sf_info.channels, nUnusedFrames * sizeof(float) * pPlayer->sf_info.channels);
} else {
//DPRINTF("No SRC, read %u frames\n", nFramesRead);
}
Expand Down Expand Up @@ -518,7 +518,7 @@ void* file_thread_fn(void * param) {
break;
}
}
} else if(pPlayer->loop) {
} else if(pPlayer->loop == 1) {
// Short read - looping so fill from loop start point in file
pPlayer->file_read_status = LOOPING;
//srcData.end_of_input = 1;
Expand Down Expand Up @@ -736,12 +736,12 @@ float get_position(AUDIO_PLAYER * pPlayer) {
return 0.0;
}

void enable_loop(AUDIO_PLAYER * pPlayer, uint8_t bLoop) {
void enable_loop(AUDIO_PLAYER * pPlayer, uint8_t nLoop) {
if(!pPlayer)
return;
getMutex();
pPlayer->loop = bLoop;
if(bLoop && pPlayer->play_pos_frames > pPlayer->loop_end_src)
pPlayer->loop = nLoop;
if(nLoop && pPlayer->play_pos_frames > pPlayer->loop_end_src)
pPlayer->play_pos_frames = pPlayer->loop_start_src;
pPlayer->file_read_status = SEEKING;
releaseMutex();
Expand All @@ -759,7 +759,7 @@ void set_loop_start_time(AUDIO_PLAYER * pPlayer, float time) {
getMutex();
pPlayer->loop_start = frames;
pPlayer->loop_start_src = pPlayer->loop_start * pPlayer->src_ratio;
if(pPlayer->loop && pPlayer->looped)
if(pPlayer->loop == 1 && pPlayer->looped)
pPlayer->file_read_status = SEEKING;
releaseMutex();
pPlayer->last_loop_start = -1;
Expand All @@ -783,7 +783,7 @@ void set_loop_end_time(AUDIO_PLAYER * pPlayer, float time) {
getMutex();
pPlayer->loop_end = frames;
pPlayer->loop_end_src = pPlayer->loop_end * pPlayer->src_ratio;
if(pPlayer->loop && pPlayer->looped)
if(pPlayer->loop == 1 && pPlayer->looped)
pPlayer->file_read_status = SEEKING;
releaseMutex();
pPlayer->last_loop_end = -1;
Expand Down Expand Up @@ -1218,8 +1218,9 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
float* output_buffers[] = {pOutA, pOutB};
bool bReverse = pPlayer->varispeed < 0.0;

if(pPlayer->play_state == STARTING && pPlayer->file_read_status != SEEKING)
if(pPlayer->play_state == STARTING && pPlayer->file_read_status != SEEKING) {
pPlayer->play_state = PLAYING;
}

if(pPlayer->play_state == PLAYING || pPlayer->play_state == STOPPING) {
if (pPlayer->time_ratio_dirty) {
Expand All @@ -1234,6 +1235,7 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
pPlayer->time_ratio_dirty = false;
}
while(pPlayer->stretcher->available() < nFrames) {
// Process data from fifo until sufficient to populate this frame (first attempt may give -1 but that's okay as we will repeat)
size_t sampsReq = min((size_t)256, pPlayer->stretcher->getSamplesRequired());
size_t nBytes = min(jack_ringbuffer_read_space(pPlayer->ringbuffer_a), jack_ringbuffer_read_space(pPlayer->ringbuffer_b));
nBytes = min(nBytes, sampsReq * sizeof(float));
Expand All @@ -1244,11 +1246,11 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
// stretch
pPlayer->stretcher->process(stretch_input_buffers, nRead / sizeof(float), nRead != nBytes);
if(nRead == 0)
break;
break; // fifo buffers run dry
}
a_count = min(pPlayer->stretcher->available(), (int)nFrames);
if(a_count < 0)
a_count = 0;
a_count = 0; // If stretcher gives fault it will respond with -1
a_count = pPlayer->stretcher->retrieve(output_buffers, a_count);
if(pPlayer->held_note != pPlayer->env_gate)
set_env_gate(pPlayer, pPlayer->held_note);
Expand All @@ -1266,6 +1268,7 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
pOutB[offset] *= pPlayer->gain;
}
}
// Advance play position based on the raw (SRC'd) frames
if(bReverse)
pPlayer->play_pos_frames -= r_count;
else
Expand All @@ -1277,17 +1280,18 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
if(cue_point_play > cue && pPlayer->play_pos_frames > pPlayer->cue_points[cue].offset) {
pPlayer->play_pos_frames = pPlayer->cue_points[cue - 1].offset;
pPlayer->env_state = ENV_RELEASE; //!@todo This looks wrong
if(pPlayer->loop)
if(pPlayer->loop == 1)
pPlayer->file_read_status = SEEKING;
else
else {
pPlayer->play_state = STOPPING;
}
} else if(a_count < nFrames && pPlayer->file_read_status == IDLE) {
// Reached end of file
pPlayer->play_pos_frames = pPlayer->crop_start_src;
pPlayer->play_state = STOPPING;
}
} else {
if(pPlayer->loop) {
if(pPlayer->loop == 1) {
if(bReverse) {
if(pPlayer->play_pos_frames <= pPlayer->loop_start_src) {
size_t i = pPlayer->loop_start_src - pPlayer->play_pos_frames;
Expand All @@ -1301,38 +1305,46 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
}
}
} else if(a_count < nFrames && pPlayer->file_read_status == IDLE) {
// Reached end of file
// No more data from file reader, e.g. reached end of file
if(bReverse)
pPlayer->play_pos_frames = pPlayer->crop_end_src;
else
pPlayer->play_pos_frames = pPlayer->crop_start_src;
pPlayer->play_state = STOPPING;
pPlayer->env_state = ENV_IDLE;
DPRINTF("libzynaudioplayer: Short read (%lu) and IDLE so STOPPING\n", a_count);
}
}
}

if(pPlayer->env_state == ENV_END)
pPlayer->env_state = ENV_IDLE;
if(pPlayer->play_state == STOPPING && pPlayer->env_state == ENV_IDLE) {
// Soft mute (not perfect for short last period of file but better than nowt)

if(pPlayer->play_state == STOPPING) {
// Soft mute (not perfect for short last period of file but better than nowt). Adds a few ms of delay.
for(size_t offset = 0; offset < a_count; ++offset) {
pOutA[offset] *= 1.0 - ((jack_default_audio_sample_t)offset / a_count);
pOutB[offset] *= 1.0 - ((jack_default_audio_sample_t)offset / a_count);
}

pPlayer->play_state = STOPPED;
pPlayer->varispeed = 0.0;
pPlayer->file_read_status = SEEKING;

//DPRINTF("libzynaudioplayer: Stopped. Used %u frames from %u in buffer to soft mute (fade). Silencing remaining %u frames (%u bytes)\n", a_count, nFrames, nFrames - a_count, (nFrames - a_count) * sizeof(jack_default_audio_sample_t));
if(pPlayer->env_state == ENV_IDLE) {
pPlayer->play_state = STOPPED;
pPlayer->varispeed = 0.0;
pPlayer->file_read_status = SEEKING;

// Reset MIDI triggers, e.g. held notes that are no longer valid
for(uint8_t i = 0; i < 128; ++i)
pPlayer->held_notes[i] = 0;
pPlayer->held_note = 0;
}

DPRINTF("libzynaudioplayer: Stopped. Used %u frames from %u in buffer to soft mute (fade). Silencing remaining %u frames (%u bytes)\n", a_count, nFrames, nFrames - a_count, (nFrames - a_count) * sizeof(jack_default_audio_sample_t));
}

// Silence remainder of frame
memset(pOutA + a_count, 0, (nFrames - a_count) * sizeof(jack_default_audio_sample_t));
memset(pOutB + a_count, 0, (nFrames - a_count) * sizeof(jack_default_audio_sample_t));
if(pPlayer->env_state != ENV_IDLE)
for(int i = 0; i < nFrames-a_count; ++i)
for(int i = 0; i < nFrames - a_count; ++i)
process_env(pPlayer);
}

Expand All @@ -1354,6 +1366,8 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
// Note off
pPlayer->held_notes[midiEvent.buffer[1]] = 0;
if(pPlayer->last_note_played == midiEvent.buffer[1]) {
if(pPlayer->loop == 3)
continue; //!@todo This is bluntly ignoring note-off but maybe we want to include envelope
pPlayer->held_note = pPlayer->sustain;
for (uint8_t i = 0; i < 128; ++i) {
if(pPlayer->held_notes[i]) {
Expand All @@ -1378,7 +1392,7 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
}
if(pPlayer->held_note)
continue;
if(pPlayer->sustain == 0) {
if(pPlayer->loop < 2 && pPlayer->sustain == 0) {
stop_playback(pPlayer);
}
}
Expand All @@ -1399,8 +1413,23 @@ int on_jack_process(jack_nframes_t nFrames, void * arg) {
pPlayer->play_state = STARTING;
}
pPlayer->last_note_played = midiEvent.buffer[1];
pPlayer->held_notes[pPlayer->last_note_played] = 1;
pPlayer->held_note = 1;
if(pPlayer->loop == 3) {
if(pPlayer->held_note) {
pPlayer->held_notes[pPlayer->last_note_played] = 0;
pPlayer->held_note = 0;
stop_playback(pPlayer);
DPRINTF("TOGGLE OFF\n");
} else {
pPlayer->held_notes[pPlayer->last_note_played] = 1;
pPlayer->held_note = 1;
DPRINTF("TOGGLE ON\n");
}
continue;
}
else {
pPlayer->held_notes[pPlayer->last_note_played] = 1;
pPlayer->held_note = 1;
}
pPlayer->stretcher->reset();
pPlayer->varispeed = pPlayer->play_varispeed;
if(!cue_point_play){
Expand Down
4 changes: 2 additions & 2 deletions zynlibs/zynaudioplayer/player.h
Expand Up @@ -151,9 +151,9 @@ float get_position(AUDIO_PLAYER * pPlayer);

/** @brief Set loop mode
* @param player_handle Handle of player provided by init_player()
* @param bLoop True to loop at end of audio
* @param nLoop 1 to loop at end of audio, 2 to play to end (ignore MIDI note-off)
*/
void enable_loop(AUDIO_PLAYER * pPlayer, uint8_t bLoop);
void enable_loop(AUDIO_PLAYER * pPlayer, uint8_t nLoop);

/* @brief Get loop mode
* @param player_handle Handle of player provided by init_player()
Expand Down

0 comments on commit f2d7b4c

Please sign in to comment.