From 4dec747fcf270c7b1f1bd2eeeb9d94b4d58199f9 Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Fri, 14 Dec 2018 17:59:56 -0500 Subject: [PATCH] Working zoom / scale in the AU host --- src/au/aulayer.h | 1 + src/au/aulayer_cocoaui.mm | 25 +- src/common/gui/#COscillatorDisplay.cpp# | 327 ++++++++++++++++++++++++ src/common/gui/.#COscillatorDisplay.cpp | 1 + src/common/gui/SurgeGUIEditor.cpp | 50 +++- src/common/gui/SurgeGUIEditor.h | 9 + 6 files changed, 410 insertions(+), 3 deletions(-) create mode 100644 src/common/gui/#COscillatorDisplay.cpp# create mode 120000 src/common/gui/.#COscillatorDisplay.cpp diff --git a/src/au/aulayer.h b/src/au/aulayer.h index bd69d68576d..c5e0721d632 100644 --- a/src/au/aulayer.h +++ b/src/au/aulayer.h @@ -12,6 +12,7 @@ class SurgeGUIEditor; class SurgeSynthesizer; typedef SurgeSynthesizer plugin; +#define GENERATE_AU_LOG struct AULOG { #ifdef GENERATE_AU_LOG diff --git a/src/au/aulayer_cocoaui.mm b/src/au/aulayer_cocoaui.mm index 2be418d65a9..a2227cc799c 100644 --- a/src/au/aulayer_cocoaui.mm +++ b/src/au/aulayer_cocoaui.mm @@ -41,6 +41,7 @@ @interface SurgeNSView : NSView { SurgeGUIEditor *editController; CFRunLoopTimerRef idleTimer; + float lastScale; } - (id) initWithSurge: (SurgeGUIEditor *) cont preferredSize: (NSSize) size; @@ -92,8 +93,10 @@ @implementation SurgeNSView - (id) initWithSurge: (SurgeGUIEditor *) cont preferredSize: (NSSize) size { self = [super initWithFrame: NSMakeRect (0, 0, size.width / 2, size.height / 2)]; + idleTimer = nil; editController = cont; + lastScale = cont->getZoomFactor() / 100.0; if (self) { AULOG::log( "Opening new editor view\n" ); @@ -105,7 +108,27 @@ - (id) initWithSurge: (SurgeGUIEditor *) cont preferredSize: (NSSize) size NSRect newSize = NSMakeRect (0, 0, vr->right - vr->left, vr->bottom - vr->top); [self setFrame:newSize]; } - + + cont->setZoomCallback( [cont,self]() { + AULOG::log( "In the Zoom Callback back in Cocoa to %d\n", cont->getZoomFactor() ); + ERect *vr; + float zf = cont->getZoomFactor() / 100.0; + if (cont->getRect(&vr)) + { + NSRect newSize = NSMakeRect (0, 0, + (int)( (vr->right - vr->left) * zf ), + (int)( (vr->bottom - vr->top) * zf ) ); + AULOG::log( "Scalining display and unit square by %lf\n", zf ); + [self scaleUnitSquareToSize:NSMakeSize( zf / lastScale, zf / lastScale )]; + lastScale = zf; + + AULOG::log( "Resetting window size\n" ); + [self setFrame:newSize]; + } + + } + ); + CFTimeInterval TIMER_INTERVAL = .05; // In SurgeGUISynthesizer.h it uses 50 ms CFRunLoopTimerContext TimerContext = {0, self, NULL, NULL, NULL}; CFAbsoluteTime FireTime = CFAbsoluteTimeGetCurrent() + TIMER_INTERVAL; diff --git a/src/common/gui/#COscillatorDisplay.cpp# b/src/common/gui/#COscillatorDisplay.cpp# new file mode 100644 index 00000000000..56b568d80cb --- /dev/null +++ b/src/common/gui/#COscillatorDisplay.cpp# @@ -0,0 +1,327 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright 2005 Claes Johanson & Vember Audio +//------------------------------------------------------------------------------------------------------- +#include "COscillatorDisplay.h" +#include "Oscillator.h" +#include +#include "unitconversion.h" + +const float disp_pitch = 90.15f - 48.f; +const int wtbheight = 12; + +extern CFontRef surge_minifont; + +void COscillatorDisplay::draw(CDrawContext* dc) +{ + pdata tp[n_scene_params]; + tp[oscdata->pitch.param_id_in_scene].f = 0; + for (int i = 0; i < n_osc_params; i++) + tp[oscdata->p[i].param_id_in_scene].i = oscdata->p[i].val.i; + Oscillator* osc = spawn_osc(oscdata->type.val.i, storage, oscdata, tp); + + cdisurf->begin(); + cdisurf->clear(0xffffffff); + + int w = cdisurf->getWidth(); + int h2 = cdisurf->getHeight(); + int h = h2; + assert(h < 512); + if (uses_wavetabledata(oscdata->type.val.i)) + h -= wtbheight; + + unsigned int column[512]; + int column_d[512]; + float lastval = 0; + int midline = h >> 1; + int topline = midline - 0.4f * h; + int bottomline = midline + 0.4f * h; + const int aa_bs = 4; + const int aa_samples = 1 << aa_bs; + int last_imax = -1, last_imin = -1; + if (osc) + { + // srand(2); + float disp_pitch_rs = disp_pitch + 12.0 * log2(dsamplerate / 44100.0); + bool use_display = osc->allow_display(); + if (use_display) + osc->init(disp_pitch_rs, true); + int block_pos = block_size_os; + for (int y = 0; y < h2; y++) + column_d[y] = 0; + + for (int x = 0; x < getWidth(); x++) + { + for (int y = 0; y < h2; y++) + column[y] = 0; + for (int s = 0; s < aa_samples; s++) + { + if (use_display && (block_pos >= block_size_os)) + { + if (uses_wavetabledata(oscdata->type.val.i)) + { + storage->CS_WaveTableData.enter(); + osc->process_block(disp_pitch_rs); + block_pos = 0; + storage->CS_WaveTableData.leave(); + } + else + { + osc->process_block(disp_pitch_rs); + block_pos = 0; + } + } + + float val = 0.f; + if (use_display) + val = -osc->output[block_pos]; + + val = (float)((0.5f + 0.4f * val) * h); + lastval = val; + float v_min = val; + float v_max = val; + + v_min = val - 0.5f; + v_max = val + 0.5f; + int imin = (int)v_min; + int imax = (int)v_max; + float imax_frac = (v_max - imax); + float imin_frac = 1 - (v_min - imin); + + if (imax == imin) + imax++; + + if (imin < 0) + imin = 0; + int dimax = imax, dimin = imin; + + if ((x > 0) || (s > 0)) + { + if (dimin > last_imax) + dimin = last_imax; + else if (dimax < last_imin) + dimax = last_imin; + } + dimin = limit_range(dimin, 0, h); + dimax = limit_range(dimax, 0, h); + + // int yp = (int)((float)(size.height() * (-osc->output[block_pos]*0.5+0.5))); + // yp = limit_range(yp,0,h-1); + + column[dimin] += ((int)((float)imin_frac * 255.f)); + column[dimax + 1] += ((int)((float)imax_frac * 255.f)); + for (int b = (dimin + 1); b < (dimax + 1); b++) + { + column_d[b & 511] = aa_samples; + } + last_imax = imax; + last_imin = imin; + block_pos++; + for (int y = 0; y < h; y++) + { + if (column_d[y] > 0) + column[y] += 256; + column_d[y]--; + } + } + column[midline] = max((unsigned int)64 << aa_bs, column[midline]); + column[topline] = max((unsigned int)32 << aa_bs, column[topline]); + column[bottomline] = max((unsigned int)32 << aa_bs, column[bottomline]); + for (int y = 0; y < h2; y++) + { + cdisurf->setPixel(x, y, coltable[min((unsigned int)255, (column[y] >> aa_bs))]); + } + } + _aligned_free(osc); + // srand( (unsigned)time( NULL ) ); + } + cdisurf->commit(); + auto size = getViewSize(); + cdisurf->draw(dc, size); + + if (uses_wavetabledata(oscdata->type.val.i)) + { + CRect wtlbl(size); + wtlbl.right -= 1; + wtlbl.top = wtlbl.bottom - wtbheight; + rmenu = wtlbl; + rmenu.inset(12, 0); + char wttxt[256]; + + storage->CS_WaveTableData.enter(); + + int wtid = oscdata->wt.current_id; + if ((wtid >= 0) && (wtid < storage->wt_list.size())) + { + strcpy(wttxt, storage->wt_list.at(wtid).name.c_str()); + } + else if (oscdata->wt.flags & wtf_is_sample) + { + strcpy(wttxt, "(Patch Sample)"); + } + else + { + strcpy(wttxt, "(Patch Wavetable)"); + } + + storage->CS_WaveTableData.leave(); + + char* r = strrchr(wttxt, '.'); + if (r) + *r = 0; + // VSTGUI::CColor fgcol = cdisurf->int_to_ccol(coltable[255]); + VSTGUI::CColor fgcol = {0xff, 0xA0, 0x10, 0xff}; + dc->setFillColor(fgcol); + dc->drawRect(rmenu, kDrawFilled); + dc->setFontColor(kBlackCColor); + dc->setFont(surge_minifont); + // strupr(wttxt); + dc->drawString(wttxt, rmenu, kCenterText, false); + + /*CRect wtlbl_status(size); + wtlbl_status.bottom = wtlbl_status.top + wtbheight; + dc->setFontColor(kBlackCColor); + if(oscdata->wt.flags & wtf_is_sample) dc->drawString("IS + SAMPLE",wtlbl_status,false,kRightText);*/ + + rnext = wtlbl; + rnext.left = rmenu.right; //+ 1; + rprev = wtlbl; + rprev.right = rmenu.left; //- 1; + dc->setFillColor(fgcol); + dc->drawRect(rprev, kDrawFilled); + dc->drawRect(rnext, kDrawFilled); + dc->setFrameColor(kBlackCColor); + for (int a = 0; a < 4; a++) + { + CPoint p1(rprev.left + 4 + a, rprev.top + (rprev.getHeight() * 0.5) - a); + CPoint p2 = p1; + p2.y += (a << 1) + 1; + dc->drawLine(p1, p2); + + CPoint p3(rnext.right - 4 - a, rnext.top + (rnext.getHeight() * 0.5) - a); + CPoint p4 = p3; + p4.y += (a << 1) + 1; + dc->drawLine(p3, p4); + } + } + + setDirty(false); +} + +bool COscillatorDisplay::onDrop(IDataPackage* drag, const CPoint& where) +{ + /*long size,type; + char *filename = (char*)drag->first(size,type); + //while(filename) + if(filename) + { + if(type == CDragContainer::kFile) + { + strncpy(oscdata->wt.queue_filename, filename, 255); + } +// filename = (char*)drag->next(size,type); + }*/ + return true; +} + +CMouseEventResult COscillatorDisplay::onMouseDown(CPoint& where, const CButtonState& button) +{ + if (!(button & kLButton)) + return kMouseDownEventHandledButDontNeedMovedOrUpEvents; + + assert(oscdata); + + if (!uses_wavetabledata(oscdata->type.val.i) || (where.y < rmenu.top)) + { + controlstate = 1; + lastpos.x = where.x; + return kMouseEventHandled; + } + else if (uses_wavetabledata(oscdata->type.val.i)) + { + int diff = 0; + if (rprev.pointInside(where)) + { + diff = -1; + } + else if (rnext.pointInside(where)) + { + diff = 1; + } + if (diff) + { + oscdata->wt.queue_id = + (oscdata->wt.current_id + diff + storage->wt_list.size()) % storage->wt_list.size(); + } + else if (rmenu.pointInside(where)) + { + CRect menurect(0, 0, 0, 0); + menurect.offset(where.x, where.y); + COptionMenu* contextMenu = new COptionMenu(menurect, 0, 0, 0, 0, kNoDrawStyle); + + for (int c = 0; c < storage->wt_category.size(); c++) + { + char name[namechars]; + COptionMenu* subMenu = new COptionMenu(getViewSize(), 0, c, 0, 0, kNoDrawStyle); + subMenu->setNbItemsPerColumn(32); + int sub = 0; + int p; + for (p = 0; p < storage->wt_list.size(); p++) + { + if (storage->wt_list[p].category == c) + { + sprintf(name, "%s", storage->wt_list[p].name.c_str()); + auto actionItem = new CCommandMenuItem(name); + auto action = [this, p](CCommandMenuItem* item) { this->loadWavetable(p); }; + + actionItem->setActions(action, nullptr); + subMenu->addEntry(actionItem); + + sub++; + } + } + strncpy(name, storage->wt_category[c].name.c_str(), namechars); + contextMenu->addEntry(subMenu, name); + + subMenu->forget(); // viktigt, så att refcounter blir rätt + } + + getFrame()->addView(contextMenu); // add to frame + contextMenu->setDirty(); + -contextMenu->popup(); + contextMenu->onMouseDown(where, kLButton); // <-- modal menu loop is here + // getFrame()->looseFocus(pContext); + + getFrame()->removeView(contextMenu, true); // remove from frame and forget + } + } + return kMouseDownEventHandledButDontNeedMovedOrUpEvents; +} + +void COscillatorDisplay::loadWavetable(int id) +{ + if (id >= 0 && (id < storage->wt_list.size())) + { + oscdata->wt.queue_id = id; + } +} + +CMouseEventResult COscillatorDisplay::onMouseUp(CPoint& where, const CButtonState& buttons) +{ + if (controlstate) + { + controlstate = 0; + } + return kMouseEventHandled; +} +CMouseEventResult COscillatorDisplay::onMouseMoved(CPoint& where, const CButtonState& buttons) +{ + if (controlstate) + { + /*oscdata->startphase.val.f -= 0.005f * (where.x - lastpos.x); + oscdata->startphase.val.f = limit_range(oscdata->startphase.val.f,0.f,1.f); + lastpos.x = where.x; + invalid();*/ + } + return kMouseEventHandled; +} diff --git a/src/common/gui/.#COscillatorDisplay.cpp b/src/common/gui/.#COscillatorDisplay.cpp new file mode 120000 index 00000000000..bb7253394f3 --- /dev/null +++ b/src/common/gui/.#COscillatorDisplay.cpp @@ -0,0 +1 @@ +paul@PWLaptop.local.53194 \ No newline at end of file diff --git a/src/common/gui/SurgeGUIEditor.cpp b/src/common/gui/SurgeGUIEditor.cpp index f3d2d4d9362..264ae14b263 100644 --- a/src/common/gui/SurgeGUIEditor.cpp +++ b/src/common/gui/SurgeGUIEditor.cpp @@ -20,8 +20,10 @@ #include "SurgeBitmaps.h" #include "CNumberField.h" -/*#if TARGET_AUDIOUNIT +#if TARGET_AUDIOUNIT #include "aulayer.h" +#endif +/* #elif TARGET_VST3 #include "surgeprocessor.h" #elif TARGET_VST2 @@ -63,6 +65,7 @@ enum special_tags tag_about, tag_mod_source0, tag_mod_source_end = tag_mod_source0 + n_modsources, + tag_mp_zoom, // tag_metaparam, // tag_metaparam_end = tag_metaparam+n_customcontrollers, start_paramtags, @@ -126,11 +129,13 @@ SurgeGUIEditor::SurgeGUIEditor(void* effect, SurgeSynthesizer* synth) : super(ef #ifdef TARGET_VST3 _idleTimer = new CVSTGUITimer([this](CVSTGUITimer* timer) { idle(); }, 50, false); #endif + zoom_callback = [](){ }; + zoomFactor = 100; } SurgeGUIEditor::~SurgeGUIEditor() { - if (frame) + if (frame ) { getFrame()->unregisterKeyboardHook(this); frame->removeAll(true); @@ -1062,6 +1067,22 @@ void SurgeGUIEditor::openOrRecreateEditor() getSurgeBitmap(IDB_BUTTON_ABOUT), nopoint, false); frame->addView(b_about); + // ZOOM CONTROL + CHSwitch2* mp_zoom = + new CHSwitch2(CRect( 892-77, 526, 892 - 40, 526 + 12 ), this, tag_mp_zoom, 2, 12, 1, 2, + getSurgeBitmap(IDB_BUTTON_MINUSPLUS), nopoint, false); + frame->addView(mp_zoom); + CTextLabel *Comments = new + CTextLabel(CRect( 892-137, 526, 892 - 77, 526 + 12 ), "Zoom" ); + + Comments->setTransparency(true); + Comments->setFont(minifont); + Comments->setFontColor( kBlackCColor ); + Comments->setHoriAlign(kRightText); + frame->addView(Comments); + + // END ZOOM CONTROL + infowindow = new CParameterTooltip(CRect(0, 0, 0, 0)); frame->addView(infowindow); @@ -1854,6 +1875,16 @@ void SurgeGUIEditor::valueChanged(CControl* control) return; } break; + case tag_mp_zoom: + { + if (control->getValue() > 0.5f) + zoomInDir( 1 ); + else + zoomInDir( -1 ); + return; + + } + break; case tag_osc_select: { current_osc = (int)(control->getValue() * 2.f + 0.5f); @@ -2220,4 +2251,19 @@ bool SurgeGUIEditor::showPatchStoreDialog(patchdata* p, return false; } +void SurgeGUIEditor::zoomInDir( int dir ) +{ + if( dir > 0 ) + { + zoomFactor += 10; + } + else + { + zoomFactor -= 10; + } + if( zoomFactor < 50 ) zoomFactor = 50; + if( zoomFactor > 300 ) zoomFactor = 300; + zoom_callback(); +} + //------------------------------------------------------------------------------------------------ diff --git a/src/common/gui/SurgeGUIEditor.h b/src/common/gui/SurgeGUIEditor.h index 47f8d348117..81e4e381ff2 100644 --- a/src/common/gui/SurgeGUIEditor.h +++ b/src/common/gui/SurgeGUIEditor.h @@ -86,6 +86,15 @@ class SurgeGUIEditor : public EditorType, public IControlListener, public IKeybo vector* patch_category, int startcategory); + + void zoomInDir( int dir ); + int zoomFactor; + public: + void setZoomCallback( std::function< void() > f ) { zoom_callback = f; } + int getZoomFactor() { return zoomFactor; } + private: + std::function< void() > zoom_callback; + SurgeBitmaps bitmap_keeper; CControl* vu[16];