Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
daisyy-hardware
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
sdiy
daisyy
daisyy-hardware
Commits
7ffaf3a8
Commit
7ffaf3a8
authored
Dec 8, 2023
by
David Huss
Browse files
Options
Downloads
Plain Diff
Merge branch 'looper2'
parents
2290274a
b5bb5db3
No related branches found
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
code/daisy-looper/daisy-looper.ino
+1
-1
1 addition, 1 deletion
code/daisy-looper/daisy-looper.ino
code/daisy-looper/looper.h
+363
-234
363 additions, 234 deletions
code/daisy-looper/looper.h
code/daisy-looper/ui.h
+44
-23
44 additions, 23 deletions
code/daisy-looper/ui.h
with
408 additions
and
258 deletions
code/daisy-looper/daisy-looper.ino
+
1
−
1
View file @
7ffaf3a8
...
...
@@ -380,7 +380,7 @@ void loop() {
// Delaytime is in samples
if
(
!
isnan
(
p5
))
{
lfo_amount
=
p5
;
}
if
(
!
isnan
(
p6
))
{
delaytime
=
100.0f
+
p6
*
23900.0f
;
}
if
(
!
isnan
(
p7
))
{
reverbmix
=
p7
;
Serial
.
print
(
"Reverb was not NaN: "
);
Serial
.
println
(
reverbmix
);
}
if
(
!
isnan
(
p7
))
{
reverbmix
=
p7
;
}
// Render the UI (frame rate limited by UI_MAX_FPS in ui.h)
// double start = millis();
...
...
This diff is collapsed.
Click to expand it.
code/daisy-looper/looper.h
+
363
−
234
View file @
7ffaf3a8
#ifndef Looper_h
#define Looper_h
#pragma once
#include
"luts.h"
namespace
atoav
{
...
...
@@ -17,267 +18,395 @@ enum RecStartMode {
REC_START_MODE_LAST
,
};
enum
PlaybackState
{
PLAYBACK_STATE_STOPPED
,
PLAYBACK_STATE_LOOP
,
PLAYBACK_STATE_MULTILOOP
,
PLAYBACK_STATE_MIDI
,
PLAYBACK_STATE_LAST
,
};
enum
RecordingState
{
REC_STATE_EMPTY
,
REC_STATE_RECORDING
,
REC_STATE_OVERDUBBING
,
REC_STATE_ERASING
,
REC_STATE_NONE
,
REC_STATE_LAST
,
};
// =================================================
// = H E A D =
// =================================================
class
Head
{
public:
Head
();
void
activate
();
void
deactivate
();
bool
isActive
();
void
setPosition
(
float
value
);
void
setIncrement
(
float
value
);
void
incrementBy
(
float
value
);
void
update
();
float
read
();
float
increment
=
1.0f
;
private:
bool
active
=
true
;
float
position
=
0.0f
;
};
Head
::
Head
()
{
}
void
Head
::
activate
()
{
this
->
active
=
true
;
}
void
Head
::
deactivate
()
{
this
->
active
=
false
;
}
bool
Head
::
isActive
()
{
return
active
;
}
void
Head
::
setPosition
(
float
value
)
{
this
->
position
=
value
;
}
void
Head
::
setIncrement
(
float
value
)
{
this
->
increment
=
value
;
}
void
Head
::
incrementBy
(
float
value
)
{
this
->
position
+=
value
;
}
void
Head
::
update
()
{
this
->
position
+=
this
->
increment
;
}
float
Head
::
read
()
{
return
this
->
position
;
}
// =================================================
// = L O O P E R =
// =================================================
class
Looper
{
public:
void
Init
(
float
*
buf
,
size_t
length
)
{
Looper
();
void
Init
(
float
*
buf
,
size_t
buf_size
);
void
SetRecord
();
void
SetOverdub
();
void
SetErase
();
void
SetStopWriting
();
bool
isWriting
();
void
ResetRecHead
();
void
SetLoop
(
float
loop_start_time
,
float
loop_length_time
);
void
Record
(
float
in
);
float
Process
();
float
*
getBuffer
();
size_t
getBufferLength
();
void
setRecPitchMode
(
RecPitchMode
mode
);
void
setRecStartMode
(
RecStartMode
mode
);
float
GetPlayhead
();
float
*
GetPlayheads
();
float
GetRecHead
();
bool
toggleRecMode
();
void
setRecModeFull
();
void
setRecModeLoop
();
void
setRecModeFullShot
();
void
setRecModeLoopShot
();
void
setPlaybackSpeed
(
float
increment
);
void
addToPlayhead
(
float
value
);
float
loop_start_f
=
0.0f
;
float
loop_length_f
=
1.0f
;
RecPitchMode
rec_pitch_mode
=
REC_PITCH_MODE_NORMAL
;
RecStartMode
rec_start_mode
=
REC_START_MODE_BUFFER
;
PlaybackState
playback_state
=
PLAYBACK_STATE_LOOP
;
RecordingState
recording_state
=
REC_STATE_EMPTY
;
private:
static
const
size_t
kFadeLength
=
200
;
static
const
size_t
kMinLoopLength
=
2
*
kFadeLength
;
float
*
buffer
;
size_t
buffer_length
=
0
;
Head
playheads
[
9
];
Head
rec_head
;
size_t
loop_start
=
0
;
size_t
loop_length
=
48000
;
bool
stop_after_recording
=
false
;
bool
stay_within_loop
=
true
;
};
Looper
::
Looper
()
{}
void
Looper
::
Init
(
float
*
buf
,
size_t
buf_size
)
{
buffer
=
buf
;
buffer_length
=
length
;
// Reset buffer contents to zero
buffer_length
=
buf_size
;
memset
(
buffer
,
0
,
sizeof
(
float
)
*
buffer_length
);
}
RecPitchMode
rec_pitch_mode
=
REC_PITCH_MODE_NORMAL
;
RecStartMode
rec_start_mode
=
REC_START_MODE_BUFFER
;
void
Looper
::
SetRecord
()
{
recording_state
=
REC_STATE_RECORDING
;
ResetRecHead
();
rec_head
.
activate
();
}
void
Looper
::
SetOverdub
()
{
recording_state
=
REC_STATE_OVERDUBBING
;
ResetRecHead
();
rec_head
.
activate
();
}
void
Looper
::
SetErase
()
{
recording_state
=
REC_STATE_ERASING
;
ResetRecHead
();
rec_head
.
activate
();
}
void
Looper
::
SetStopWriting
()
{
recording_state
=
REC_STATE_NONE
;
rec_head
.
deactivate
();
}
void
SetRecording
(
bool
is_recording
,
bool
is_overdub
)
{
this
->
is_overdub
=
is_overdub
;
this
->
is_recording
=
is_recording
||
is_overdub
;
//Initialize recording head position on start
// if (rec_env_pos_inc <= 0 && is_recording) {
if
(
is_recording
)
{
// rec_head = (loop_start + play_head) % buffer_length;
bool
Looper
::
isWriting
()
{
return
recording_state
==
REC_STATE_RECORDING
||
recording_state
==
REC_STATE_OVERDUBBING
||
recording_state
==
REC_STATE_ERASING
;
}
void
Looper
::
ResetRecHead
()
{
if
(
isWriting
())
{
switch
(
rec_start_mode
)
{
case
REC_START_MODE_LOOP
:
rec_head
=
(
loop_start
)
%
buffer_length
;
rec_head
.
setPosition
(
loop_start
%
buffer_length
)
;
break
;
case
REC_START_MODE_BUFFER
:
rec_head
=
0.0f
;
rec_head
.
setPosition
(
0.0f
)
;
break
;
case
REC_START_MODE_PLAYHEAD
:
rec_head
=
fmod
(
loop_start
+
play
_
head
,
float
(
buffer_length
));
rec_head
.
setPosition
(
fmod
(
loop_start
+
playhead
s
[
0
].
read
()
,
float
(
buffer_length
))
)
;
break
;
}
is_empty
=
false
;
}
// When record switch changes state it effectively
// sets ramp to rising/falling, providing a
// fade in/out in the beginning and at the end of
// the recorded region.
rec_env_pos_inc
=
is_recording
?
1
:
-
1
;
}
void
SetLoop
(
const
float
loop_start_time
,
const
float
loop_length_time
)
{
void
Looper
::
SetLoop
(
float
loop_start_time
,
float
loop_length_time
)
{
if
(
!
isnan
(
loop_start_time
))
{
loop_start_f
=
loop_start_time
;
// Set the start of the next loop
pending_loop_start
=
static_cast
<
size_t
>
(
loop_start_time
*
(
buffer_length
-
1
));
// If the current loop start is not set yet, set it too
if
(
!
is_loop_set
)
loop_start
=
pending_loop_start
;
loop_start
=
static_cast
<
size_t
>
(
loop_start_time
*
(
buffer_length
-
1
));
}
if
(
!
isnan
(
loop_length_time
))
{
loop_length_f
=
loop_length_time
;
// Set the length of the next loop
pendingloop_length
=
max
(
kMinLoopLength
,
static_cast
<
size_t
>
(
loop_length_time
*
buffer_length
));
// CHECK if this is truly good
// loop_length = pendingloop_length;
// loop_length = pendingloop_length;
//If the current loop length is not set yet, set it too
if
(
!
is_loop_set
)
loop_length
=
pendingloop_length
;
loop_length
=
max
(
kMinLoopLength
,
static_cast
<
size_t
>
(
loop_length_time
*
buffer_length
));
}
is_loop_set
=
true
;
}
void
Record
(
float
in
)
{
// Calculate iterator position on the record level ramp.
if
(
rec_env_pos_inc
>
0
&&
rec_env_pos
<
kFadeLength
||
rec_env_pos_inc
<
0
&&
rec_env_pos
>
0
)
{
rec_env_pos
+=
rec_env_pos_inc
;
}
// If we're in the middle of the ramp - record to the buffer.
if
(
rec_env_pos
>
0
)
{
// Calculate fade in/out
float
rec_attenuation
=
static_cast
<
float
>
(
rec_env_pos
)
/
static_cast
<
float
>
(
kFadeLength
);
if
(
this
->
is_overdub
)
{
buffer
[
int
(
rec_head
)]
+=
in
*
rec_attenuation
;
}
else
{
buffer
[
int
(
rec_head
)]
=
in
*
rec_attenuation
+
buffer
[
int
(
rec_head
)]
*
(
1.f
-
rec_attenuation
);
void
Looper
::
Record
(
float
in
)
{
// Overwrite/Add/Erase the buffer depending on the mode
switch
(
recording_state
)
{
case
REC_STATE_RECORDING
:
buffer
[
int
(
rec_head
.
read
())]
=
in
;
break
;
case
REC_STATE_OVERDUBBING
:
buffer
[
int
(
rec_head
.
read
())]
+=
in
;
break
;
case
REC_STATE_ERASING
:
buffer
[
int
(
rec_head
.
read
())]
=
0.0f
;
break
;
}
// Set recording pitch mode
// Advance the recording head if needed
if
(
isWriting
())
{
// Set Recording head increment depending on the mode
switch
(
rec_pitch_mode
)
{
case
REC_PITCH_MODE_NORMAL
:
rec_head
+=
1.0f
;
rec_head
.
setIncrement
(
1.0f
)
;
break
;
case
REC_PITCH_MODE_UNPITCHED
:
rec_head
+=
playback_
increment
;
rec_head
.
setIncrement
(
playheads
[
0
].
increment
)
;
break
;
case
REC_PITCH_MODE_PITCHED
:
if
(
play
back_
increment
!=
0.0
)
{
rec_head
+=
1.0f
/
playback_
increment
;
if
(
play
heads
[
0
].
increment
!=
0.0
)
{
rec_head
.
setIncrement
(
1.0f
/
playheads
[
0
].
increment
)
;
}
break
;
}
// Increment recording head
rec_head
.
update
();
//
Different recording
mode
s
//
Limit the position of the rec head depending on the active
mode
if
(
!
stop_after_recording
)
{
if
(
!
stay_within_loop
)
{
// record into whole buffer
rec_head
=
fmod
(
rec_head
,
float
(
buffer_length
));
rec_head
.
setPosition
(
fmod
(
rec_head
.
read
()
,
float
(
buffer_length
))
)
;
}
else
{
// Limit rec head to stay inside the loop
rec_head
=
fmod
(
rec_head
,
float
(
loop_start
+
loop_length
));
rec_head
=
max
(
float
(
loop_start
),
rec_head
);
rec_head
.
setPosition
(
fmod
(
rec_head
.
read
()
,
float
(
loop_start
+
loop_length
))
)
;
rec_head
.
setPosition
(
max
(
float
(
loop_start
),
rec_head
.
read
())
);
}
}
else
{
// Stop at end (either end of buffer or end of loop)
if
(
!
stay_within_loop
)
{
if
(
rec_head
>
buffer_length
)
{
Set
Recording
(
false
,
false
);
}
if
(
rec_head
.
read
()
>
buffer_length
)
{
Set
StopWriting
(
);
}
}
else
{
if
(
rec_head
>
loop_start
+
loop_length
)
{
Set
Recording
(
false
,
false
);
}
if
(
rec_head
.
read
()
>
loop_start
+
loop_length
)
{
Set
StopWriting
(
);
}
}
}
if
(
rec_head
>
buffer_length
)
{
rec_head
=
0.0f
;
}
else
if
(
rec_head
<
0
)
{
rec_head
=
buffer_length
;
// Ensure the Rec-Head is never without bounds, even when running backwards
if
(
rec_head
.
read
()
>
buffer_length
)
{
rec_head
.
setPosition
(
0.0f
);
}
else
if
(
rec_head
.
read
()
<
0
)
{
rec_head
.
setPosition
(
buffer_length
);
}
}
}
float
Process
()
{
// Early return if the buffer is empty
if
(
is_empty
)
{
float
Looper
::
Process
()
{
// Early return if buffer is empty or not playing to save performance
if
(
recording_state
==
REC_STATE_EMPTY
||
playback_state
==
PLAYBACK_STATE_STOPPED
)
{
return
0
;
}
// Variables for the Playback from the Buffer
float
attenuation
=
1
;
float
output
=
0
;
// Calculate fade in/out
if
(
play_head
<
kFadeLength
)
{
attenuation
=
static_cast
<
float
>
(
play_head
)
/
static_cast
<
float
>
(
kFadeLength
);
// Deactivate all playheads except first if playback state is Loop
switch
(
playback_state
)
{
case
PLAYBACK_STATE_LOOP
:
playheads
[
0
].
activate
();
for
(
size_t
i
=
1
;
i
<
9
;
i
++
)
{
playheads
[
i
].
deactivate
();
}
else
if
(
play_head
>=
loop_length
-
kFadeLength
)
{
attenuation
=
static_cast
<
float
>
(
loop_length
-
play_head
)
/
static_cast
<
float
>
(
kFadeLength
);
break
;
case
PLAYBACK_STATE_MULTILOOP
:
for
(
size_t
i
=
0
;
i
<
9
;
i
++
)
{
playheads
[
i
].
activate
();
}
break
;
case
PLAYBACK_STATE_STOPPED
:
for
(
size_t
i
=
0
;
i
<
9
;
i
++
)
{
playheads
[
i
].
deactivate
();
}
break
;
}
double
mix
=
0.0
;
for
(
size_t
i
=
0
;
i
<
9
;
i
++
)
{
// Skip inactive playheads
if
(
!
playheads
[
i
].
isActive
())
continue
;
// Ensure we are actually inside the buffer
auto
play_pos
=
int
(
loop_start
+
play
_
head
)
%
buffer_length
;
int
play_pos
=
int
(
loop_start
+
playhead
s
[
i
].
read
()
)
%
buffer_length
;
// Read from the buffer
output
=
buffer
[
play_pos
]
*
attenuation
;
mix
+
=
buffer
[
play_pos
];
// Advance playhead
by the increment
play
_
head
+=
playback_increment
;
// Advance
the
playhead
playhead
s
[
i
].
update
()
;
// Ensure the playhead stays within bounds of the loop
if
(
play_head
>=
loop_length
)
{
loop_start
=
pending_loop_start
;
loop_length
=
pendingloop_length
;
play_head
=
0
;
}
else
if
(
play_head
<=
0
)
{
loop_start
=
pending_loop_start
;
loop_length
=
pendingloop_length
;
play_head
=
loop_length
;
if
((
playheads
[
i
].
read
())
>=
loop_length
)
{
playheads
[
i
].
setPosition
(
0.0f
);
}
else
if
(
playheads
[
i
].
read
()
<=
0.0f
)
{
playheads
[
i
].
setPosition
(
loop_length
);
}
}
return
saturate
(
mix
);
}
// Return the attenuated signal
return
output
*
attenuation
;
float
Looper
::
GetPlayhead
()
{
return
float
(
playheads
[
0
].
read
())
/
float
(
buffer_length
)
;
}
float
GetPlayhead
()
{
return
float
(
play_head
)
/
float
(
buffer_length
);
float
*
Looper
::
GetPlayheads
()
{
static
float
playhead_positions
[
9
];
for
(
size_t
i
=
0
;
i
<
9
;
i
++
)
{
playhead_positions
[
i
]
=
float
(
playheads
[
i
].
read
())
/
float
(
buffer_length
);
Serial
.
print
(
playhead_positions
[
i
]);
Serial
.
print
(
" "
);
}
Serial
.
println
(
""
);
return
playhead_positions
;
}
float
GetRecHead
()
{
return
float
(
rec_head
)
/
float
(
buffer_length
);
float
Looper
::
GetRecHead
()
{
return
float
(
rec_head
.
read
()
)
/
float
(
buffer_length
);
}
bool
toggleRecMode
()
{
bool
Looper
::
toggleRecMode
()
{
stay_within_loop
=
!
stay_within_loop
;
return
stay_within_loop
;
}
void
setRecModeFull
()
{
void
Looper
::
setRecModeFull
()
{
stay_within_loop
=
false
;
stop_after_recording
=
false
;
}
void
setRecModeLoop
()
{
void
Looper
::
setRecModeLoop
()
{
stay_within_loop
=
true
;
stop_after_recording
=
false
;
}
void
setRecModeFullShot
()
{
void
Looper
::
setRecModeFullShot
()
{
stay_within_loop
=
false
;
stop_after_recording
=
true
;
}
void
setRecModeLoopShot
()
{
void
Looper
::
setRecModeLoopShot
()
{
stay_within_loop
=
true
;
stop_after_recording
=
true
;
}
void
setPlaybackSpeed
(
float
increment
)
{
playback_increment
=
increment
;
void
Looper
::
setPlaybackSpeed
(
float
increment
)
{
switch
(
playback_state
)
{
case
PLAYBACK_STATE_LOOP
:
playheads
[
0
].
setIncrement
(
increment
);
break
;
case
PLAYBACK_STATE_MULTILOOP
:
playheads
[
0
].
setIncrement
(
increment
);
for
(
size_t
i
=
1
;
i
<
9
;
i
++
)
{
playheads
[
i
].
setIncrement
(
increment
+
increment
/
(
1
+
i
));
}
void
addToPlayhead
(
float
value
)
{
play_head
+=
value
;
break
;
}
float
*
getBuffer
()
{
return
buffer
;
}
size_t
getBufferLength
()
{
return
buffer_length
;
void
Looper
::
addToPlayhead
(
float
value
)
{
switch
(
playback_state
)
{
case
PLAYBACK_STATE_LOOP
:
playheads
[
0
].
incrementBy
(
value
);
break
;
case
PLAYBACK_STATE_MULTILOOP
:
playheads
[
0
].
incrementBy
(
value
);
for
(
size_t
i
=
1
;
i
<
9
;
i
++
)
{
playheads
[
i
].
incrementBy
(
value
+
value
/
(
1
+
i
));
}
break
;
}
}
bool
isRecording
()
{
return
is_recording
;
float
*
Looper
::
getBuffer
()
{
return
buffer
;
}
bool
isOverdubbing
()
{
return
is_overdub
;
size_t
Looper
::
getBufferLength
()
{
return
buffer_length
;
}
void
setRecPitchMode
(
RecPitchMode
mode
)
{
void
Looper
::
setRecPitchMode
(
RecPitchMode
mode
)
{
rec_pitch_mode
=
mode
;
}
void
setRecStartMode
(
RecStartMode
mode
)
{
void
Looper
::
setRecStartMode
(
RecStartMode
mode
)
{
rec_start_mode
=
mode
;
}
float
loop_length_f
=
1.0f
;
float
loop_start_f
=
0.0f
;
private
:
static
const
size_t
kFadeLength
=
200
;
static
const
size_t
kMinLoopLength
=
2
*
kFadeLength
;
float
*
buffer
;
size_t
buffer_length
=
0
;
size_t
loop_length
=
48000
;
size_t
pendingloop_length
=
0
;
size_t
loop_start
=
0
;
size_t
pending_loop_start
=
0
;
float
play_head
=
0.0f
;
float
rec_head
=
0.0f
;
float
playback_increment
=
1.0f
;
size_t
rec_env_pos
=
0
;
int32_t
rec_env_pos_inc
=
0
;
bool
is_empty
=
true
;
bool
is_loop_set
=
false
;
bool
stay_within_loop
=
false
;
bool
is_overdub
=
false
;
bool
is_recording
=
false
;
bool
stop_after_recording
=
false
;
};
};
// namespace atoav
\ No newline at end of file
#endif
\ No newline at end of file
This diff is collapsed.
Click to expand it.
code/daisy-looper/ui.h
+
44
−
23
View file @
7ffaf3a8
...
...
@@ -101,12 +101,12 @@ class Ui {
GridButton
(
"START
\n
LOOPST
\n
PLAYHD"
,
&
button_6
,
false
,
BUTTON_TYPE_MULTITOGGLE
,
0
,
"START RECORDING AT
\n\n
START--->Start of the
\n
Buffer
\n
LOOP---->Start of the
\n
Loop
\n
PLAYH--->Position of
\n
the Playhead"
),
}),
ButtonGrid
((
int
)
UI_MODE_PLAY_MENU
,
{
GridButton
(
"
LOOP
"
,
&
button_1
,
false
),
GridButton
(
"
"
,
&
button_1
,
false
),
GridButton
(
"PLAY
\n
MENU"
,
&
button_2
,
true
),
GridButton
(
"ACTIVE
\n
SUM
\n
RING"
,
&
button_3
,
false
,
BUTTON_TYPE_MULTITOGGLE
,
0
),
GridButton
(
"
DRUNK"
,
&
button_4
,
false
),
GridButton
(
"
GRAIN
"
,
&
button_5
,
false
),
GridButton
(
"
SHOT
"
,
&
button_6
,
false
),
GridButton
(
"
STOP
\n
LOOP
\n
MULTI
\n
MIDI"
,
&
button_4
,
false
,
BUTTON_TYPE_MULTITOGGLE
,
1
),
GridButton
(
"
"
,
&
button_5
,
false
),
GridButton
(
"
"
,
&
button_6
,
false
),
}),
ButtonGrid
((
int
)
UI_MODE_TRIGGER_MENU
,
{
GridButton
(
"MIDI
\n
TRIG."
,
&
button_1
,
false
),
...
...
@@ -415,25 +415,22 @@ class Ui {
if
(
ui_mode
==
UI_MODE_PLAY_MENU
&&
last_ui_mode
!=
UI_MODE_PLAY_MENU
)
{
int
n
=
1
;
// Show the setting of the current buffer
button_grids
[
n
].
grid_buttons_
[
3
].
active
=
(
int
)
activeLooper
()
->
playback_state
;
// Setup button Grid
Button
*
home_button
=
setupButtonGrid
(
n
);
// button_1.onPress([this, n](){
// });
button_3
.
onPress
([
this
,
n
](){
button_grids
[
n
].
grid_buttons_
[
2
].
next
();
buffer_summing_mode
=
(
BufferSummingMode
)
button_grids
[
n
].
grid_buttons_
[
2
].
active
;
});
// button_4.onPress([this, n](){
//
// });
// button_5.onPress([this, n](){
//
// });
// button_6.onPress([this, n](){
//
// });
button_4
.
onPress
([
this
,
n
](){
button_grids
[
n
].
grid_buttons_
[
3
].
next
();
// 0 is stop so we add one, check looper.h for definition of enum
activeLooper
()
->
playback_state
=
(
atoav
::
PlaybackState
)
(
button_grids
[
n
].
grid_buttons_
[
3
].
active
);
});
// Store the last ui mode, for the check on top
last_ui_mode
=
ui_mode
;
...
...
@@ -573,14 +570,38 @@ class Ui {
}
// Draw Playhead
switch
(
activeLooper
()
->
playback_state
)
{
case
atoav
::
PLAYBACK_STATE_LOOP
:
{
int
x_playhead
=
int
(
activeLooper
()
->
GetPlayhead
()
*
display
.
width
())
+
x_start_loop
;
display
.
drawFastVLine
(
x_playhead
,
6
,
24
,
SH110X_WHITE
);
break
;
}
case
atoav
::
PLAYBACK_STATE_MULTILOOP
:
{
float
*
playheads
=
activeLooper
()
->
GetPlayheads
();
int
x_playhead
=
0
;
for
(
size_t
i
=
0
;
i
<
9
;
i
++
)
{
x_playhead
=
int
(
playheads
[
i
]
*
display
.
width
())
+
x_start_loop
;
int
h
=
6
+
i
*
3
;
display
.
drawFastVLine
(
x_playhead
,
h
,
3
,
SH110X_WHITE
);
}
break
;
}
case
atoav
::
PLAYBACK_STATE_MIDI
:
{
int
x_playhead
=
int
(
activeLooper
()
->
GetPlayhead
()
*
display
.
width
())
+
x_start_loop
;
display
.
drawLine
(
x_playhead
,
6
,
x_playhead
,
24
,
SH110X_WHITE
);
display
.
drawFastVLine
(
x_playhead
,
6
,
24
,
SH110X_WHITE
);
break
;
}
}
// Draw Recording Indicator and Recording Head
if
(
recording_state
==
REC_STATE_RECORDING
)
{
// Draw Rec Head
int
x_rec_head
=
int
(
activeLooper
()
->
GetRecHead
()
*
display
.
width
());
display
.
drawLine
(
x_rec_head
,
10
,
x_rec_head
,
bottom
,
SH110X_WHITE
);
display
.
draw
FastV
Line
(
x_rec_head
,
10
,
bottom
,
SH110X_WHITE
);
display
.
fillCircle
(
x_rec_head
,
10
,
3
,
SH110X_WHITE
);
// Record sign
display
.
fillRect
(
0
,
0
,
13
,
13
,
SH110X_WHITE
);
...
...
@@ -593,7 +614,7 @@ class Ui {
if
(
recording_state
==
REC_STATE_OVERDUBBING
)
{
// Draw Rec Head
int
x_rec_head
=
int
(
activeLooper
()
->
GetRecHead
()
*
display
.
width
());
display
.
drawLine
(
x_rec_head
,
10
,
x_rec_head
,
bottom
,
SH110X_WHITE
);
display
.
draw
FastV
Line
(
x_rec_head
,
10
,
bottom
,
SH110X_WHITE
);
display
.
fillCircle
(
x_rec_head
,
10
,
3
,
SH110X_WHITE
);
// Overdub sign (a "plus")
...
...
@@ -620,7 +641,7 @@ class Ui {
// Activate recording and set the waveform cache to dirty
void
activateRecording
()
{
if
(
recording_state
!=
REC_STATE_RECORDING
)
{
activeLooper
()
->
SetRecord
ing
(
true
,
false
);
activeLooper
()
->
SetRecord
(
);
waveform_cache_dirty
=
true
;
recording_state
=
REC_STATE_RECORDING
;
}
...
...
@@ -646,7 +667,7 @@ class Ui {
if
(
recording_state
!=
REC_STATE_OVERDUBBING
)
{
waveform_cache_dirty
=
true
;
recording_state
=
REC_STATE_OVERDUBBING
;
activeLooper
()
->
Set
Recording
(
true
,
true
);
activeLooper
()
->
Set
Overdub
(
);
}
}
...
...
@@ -654,7 +675,7 @@ class Ui {
void
stopRecording
()
{
if
(
recording_state
!=
REC_STATE_NOT_RECORDING
)
{
recording_state
=
REC_STATE_NOT_RECORDING
;
activeLooper
()
->
Set
Recording
(
false
,
false
);
activeLooper
()
->
Set
StopWriting
(
);
}
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment