-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create App for Scope using fullscreen #76
base: production
Are you sure you want to change the base?
Changes from all commits
44ebbd3
ae27333
b52a005
2d8ab44
ed5581f
6ec4d0d
e0f2cd9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
#include "HSApplication.h" | ||
#include "HSMIDI.h" | ||
|
||
#define HEMISPHERE_MAX_CV 7680 | ||
#define HEMISPHERE_CENTER_CV 0 | ||
#define SCOPE_WIDTH 128 | ||
|
||
class BigScope : public HSApplication, public SystemExclusiveHandler { | ||
public: | ||
void Start() { | ||
last_bpm_tick = OC::CORE::ticks; | ||
bpm = 0; | ||
sample_ticks = 320; | ||
freeze = 0; | ||
last_scope_tick = 0; | ||
} | ||
|
||
void Resume() { | ||
} | ||
|
||
void Controller() { | ||
if (Clock(0)) { | ||
int this_tick = OC::CORE::ticks; | ||
int time = this_tick - last_bpm_tick; | ||
last_bpm_tick = this_tick; | ||
bpm = 1000000 / time; | ||
if (bpm > 9999) bpm = 9999; | ||
|
||
if (last_scope_tick) { | ||
int cycle_ticks = OC::CORE::ticks - last_scope_tick; | ||
sample_ticks = cycle_ticks / 64; | ||
sample_ticks = constrain(sample_ticks, 2, 64000); | ||
} | ||
last_scope_tick = OC::CORE::ticks; | ||
} | ||
|
||
if (!freeze) { | ||
last_cv = In(0); | ||
|
||
if (--sample_countdown < 1) { | ||
sample_countdown = sample_ticks; | ||
if (++sample_num > 127) sample_num = 0; | ||
int sample = Proportion(In(0), HEMISPHERE_MAX_CV, 128); | ||
sample = constrain(sample, -128, 127) + 127; | ||
snapshot[sample_num] = (uint8_t) sample; | ||
} | ||
|
||
Out(0, In(0)); | ||
} | ||
} | ||
|
||
void View() { | ||
gfxHeader("Scope"); | ||
//gfxPrint(1, 2, "Scope"); | ||
//DrawTicks(); | ||
DrawVoltage(); | ||
DrawBPM(); | ||
DrawInput1(); | ||
if (freeze) { | ||
gfxInvert(0, 24, 128, 40); | ||
} | ||
} | ||
|
||
void OnSendSysEx() { | ||
} | ||
|
||
void OnReceiveSysEx() { | ||
} | ||
|
||
///////////////////////////////////////////////////////////////// | ||
// Control handlers | ||
///////////////////////////////////////////////////////////////// | ||
void OnLeftButtonPress() { | ||
freeze = 1 - freeze; | ||
} | ||
|
||
void OnLeftButtonLongPress() { | ||
|
||
} | ||
|
||
void OnRightButtonPress() { | ||
} | ||
|
||
void OnUpButtonPress() { | ||
} | ||
|
||
void OnDownButtonPress() { | ||
} | ||
|
||
void OnDownButtonLongPress() { | ||
} | ||
|
||
void OnLeftEncoderMove(int direction) { | ||
if (sample_ticks < 32) sample_ticks += direction; | ||
else sample_ticks += direction * 10; | ||
sample_ticks = constrain(sample_ticks, 2, 64000); | ||
last_encoder_move = OC::CORE::ticks; | ||
} | ||
|
||
void OnRightEncoderMove(int direction) { | ||
} | ||
|
||
private: | ||
// BPM Calcultion | ||
int last_bpm_tick; | ||
int bpm; | ||
|
||
// CV monitor | ||
int last_cv; | ||
bool freeze; | ||
|
||
// Scope | ||
uint8_t snapshot[128]; | ||
int sample_ticks; // Ticks between samples | ||
int sample_countdown; // Last time a sample was taken | ||
int sample_num; // Current sample number at the start | ||
int last_encoder_move; // The last the the sample_ticks value was changed | ||
int last_scope_tick; // Used to auto-calculate sample countdown | ||
|
||
void DrawBPM() { | ||
gfxPrint(110, 1, bpm / 4); | ||
gfxBitmap(102, 1, 8, CLOCK_ICON); | ||
} | ||
|
||
// void DrawTicks() { | ||
// gfxPrint(40, 1, sample_ticks); | ||
// } | ||
Comment on lines
+125
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: Please remove any commented out code or uncomment this if it's needed. |
||
|
||
|
||
void gfxPrintVoltage(int cv) { | ||
int v = (cv * 100) / (12 << 7); | ||
bool neg = v < 0 ? 1 : 0; | ||
if (v < 0) v = -v; | ||
int wv = v / 100; // whole volts | ||
int dv = v - (wv * 100); // decimal | ||
gfxPrint(neg ? "-" : "+"); | ||
gfxPrint(wv); | ||
gfxPrint("."); | ||
if (dv < 10) gfxPrint("0"); | ||
gfxPrint(dv); | ||
gfxPrint("V"); | ||
Comment on lines
+131
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: Could you get some formatting done in here? Obviously it's of zero importance in the grand scheme of things, but readability is king 👑 |
||
} | ||
|
||
void DrawVoltage() { | ||
gfxBitmap(45, 3, 8, CV_ICON); | ||
gfxPos(55, 1); | ||
gfxPrintVoltage(last_cv); | ||
} | ||
|
||
void DrawInput1() { | ||
for (int s = 0; s < 128; s++) | ||
{ | ||
int x = s + sample_num; | ||
if (x > 127) x -= 128; | ||
int l = Proportion(snapshot[x], 255, 48); | ||
gfxPixel(x, (48 - l) + 14); | ||
} | ||
|
||
} | ||
|
||
}; | ||
|
||
BigScope BigScope_instance; | ||
|
||
// App stubs | ||
void BigScope_init() { | ||
BigScope_instance.BaseStart(); | ||
} | ||
|
||
// Not using O_C Storage | ||
size_t BigScope_storageSize() { return 0; } | ||
|
||
size_t BigScope_save(void *storage) { return 0; } | ||
|
||
size_t BigScope_restore(const void *storage) { return 0; } | ||
|
||
void BigScope_isr() { | ||
return BigScope_instance.BaseController(); | ||
} | ||
|
||
void BigScope_handleAppEvent(OC::AppEvent event) { | ||
if (event == OC::APP_EVENT_RESUME) { | ||
BigScope_instance.Resume(); | ||
} | ||
if (event == OC::APP_EVENT_SUSPEND) { | ||
BigScope_instance.OnSendSysEx(); | ||
} | ||
} | ||
|
||
void BigScope_loop() {} // Deprecated | ||
|
||
void BigScope_menu() { | ||
BigScope_instance.BaseView(); | ||
} | ||
|
||
void BigScope_screensaver() {} // Deprecated | ||
|
||
void BigScope_handleButtonEvent(const UI::Event &event) { | ||
// For left encoder, handle press and long press | ||
if (event.control == OC::CONTROL_BUTTON_L) { | ||
if (event.type == UI::EVENT_BUTTON_LONG_PRESS) BigScope_instance.OnLeftButtonLongPress(); | ||
else BigScope_instance.OnLeftButtonPress(); | ||
} | ||
|
||
// For right encoder, only handle press (long press is reserved) | ||
if (event.control == OC::CONTROL_BUTTON_R && event.type == UI::EVENT_BUTTON_PRESS) | ||
BigScope_instance.OnRightButtonPress(); | ||
|
||
// For up button, handle only press (long press is reserved) | ||
if (event.control == OC::CONTROL_BUTTON_UP) BigScope_instance.OnUpButtonPress(); | ||
|
||
// For down button, handle press and long press | ||
if (event.control == OC::CONTROL_BUTTON_DOWN) { | ||
if (event.type == UI::EVENT_BUTTON_PRESS) BigScope_instance.OnDownButtonPress(); | ||
if (event.type == UI::EVENT_BUTTON_LONG_PRESS) BigScope_instance.OnDownButtonLongPress(); | ||
} | ||
} | ||
Comment on lines
+198
to
+217
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is pristine 🛀 Great Job! |
||
|
||
void BigScope_handleEncoderEvent(const UI::Event &event) { | ||
// Left encoder turned | ||
if (event.control == OC::CONTROL_ENCODER_L) BigScope_instance.OnLeftEncoderMove(event.value); | ||
|
||
// Right encoder turned | ||
if (event.control == OC::CONTROL_ENCODER_R) BigScope_instance.OnRightEncoderMove(event.value); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these methods have to be defined in order to prevent null references down the line? Or is it just common practice in this repo to define all the possible event handlers?